静かなる名辞

pythonとプログラミングのこと


【python】threadingでsleep中に即座にスレッドを止める

 pythonのスレッド活用というと、こんなコードがすぐに思い浮かびます。

# エンターされるまでは数字を更新して、
# エンターされたら終了する(つもり)

import time
import threading

flag = True

def th():
    i = 0
    while flag:
        print("\r{}:".format(i), end="")
        i += 1
        time.sleep(3)

th = threading.Thread(target=th)
th.start()
input()
flag = False

 これは期待と違う動作になります(エンター押してから最大3秒後にならないと終了しない)。sleep中に条件の判定をしてくれる訳はないからです。

 どうやって意図通りの動作にするかというと、threading.Eventを使うと楽です。

threading --- スレッドベースの並列処理 — Python 3.7.4 ドキュメント

import threading

def th():
    i = 0
    while True:
        print("\r{}:".format(i), end="")
        i += 1
        if event.wait(timeout=3):
            # ここにイベントが発生したときの処理を書く
            break

event = threading.Event()
th = threading.Thread(target=th)
th.start()
input()
event.set()

 Event.waitにtimeoutを指定するとsleep代わりに使えます。要諦としては、

  • Eventの内部に持つフラグをclearメソッドでFalseに、setメソッドでTrueに切り替えられる。デフォルトはFalse
  • 内部フラグがTrueならwaitメソッドは即座に返る。Falseの場合はTrueになるまで(他スレッドがsetするまで)永遠に待つのがデフォルトの動作だが、timeoutを指定するとその期間待ってから返る
  • waitメソッドはtimeoutしたとき(だけ)はFalseを返す。それ以外はTrue

 というあたりで、活用すると面白いコードが書けます。