Python でもマルチスレッドプログラムを書いてみたらハマった
昨日の Ruby/tk で書いたマルチスレッドプログラムを Python/tkinter に移植したら、予想外の挙動に出会いました。
Ruby/Tk でマルチスレッドプログラム - minofoto and miscellaneous notes
import tkinter as tk import threading from datetime import datetime from time import sleep def update_calendar(label): while True: now = datetime.now() label.configure(text="{:04d}/{:02d}/{:02d}".format(now.year, now.month, now.day)) label.update() sleep(2) def update_clock(label): while True: now = datetime.now() label.configure(text="{:02d}:{:02d}:{:02d}".format(now.hour, now.minute, now.second)) label.update() sleep(1) root = tk.Tk() label1 = tk.Label(root, text="label1") label2 = tk.Label(root, text="label2") label1.pack() label2.pack() thread1 = threading.Thread(target=update_calendar(label1), daemon=True) thread2 = threading.Thread(target=update_clock(label2), daemon=True) thread1.start() thread2.start() root.mainloop()
これを実行すると
となってしまい、thread2 で更新されるはずの label2 に時間が表示されません。
これは、threading.Thread で引数の渡し方が間違っていたからのようです。正しくは
thread1 = threading.Thread(target=update_calendar, args=(label1,), daemon=True) thread2 = threading.Thread(target=update_clock, args=(label2,), daemon=True)
と、引数を (arg, ) とタブルにして、args=(label1,) のように 渡すべきでした。Ruby と比べるとちょっとややこしいですね。とはいえ、元の間違いのように threading.Thread(target=function(arg)) とした場合でもエラーにならずに function(arg) を実行するというのは不思議な挙動です。thread2 が実行されなかったことから、おそらくサブスレッドではなくメインスレッドで update_calendar(label1) が実行され、そこが無限ループなので止まっていたのでしょう。
Python の threading でちょっと嵌ってしまうポイントでした。