普通のサブルーチンがあったとします
def foo():
print("foo")
print("bar")
foo() # "foo"と"bar"を出力
これにyield
を挟み込むことで分割します
def foo():
print("foo")
yield 0
print("bar")
yield 0
f = foo()
f.__next__() # "foo"を出力
f.__next__() # "bar"を出力
つまりひとつの処理をyield
でイテレータにします
これをThread
に応用すれば一時停止/再開/中断(pause/resume/halt
メソッド)が実装できます
class Shred(Thread):
def __init__(actions):
Thread.__init__()
self._actions = actions
self.is_halted = False
self.is_paused = False
def run():
while True:
if self.is_paused:
continue
if self.is_halted:
return
try:
self._actions.__next__()
except StopIteration:
self.is_halted = True
return
def pause():
self.is_paused = True
def resume():
self.is_paused = False
def halt():
self.is_halted = True
(実際はフラグにEvent
を使ったほうがいいです)
これによって一時停止/再開/中断のチョークポイントをyield
のみで表現でき、
可読性の向上に加え、他のロジックの記述に集中できるようになります
def baz():
for n in range(10):
print(n)
time.sleep(1)
yield 0
s = Shred(baz())
s.start()
time.sleep(2)
# 0
# 1
# 2
s.pause()
time.sleep(2)
# 2秒間出力なし
s.resume()
time.sleep(2)
# 3
# 4
# 5
s.halt()
# 出力終了
ちなみにこのイテレータは内容をすべて実行すれば元のサブルーチンに戻ります
list(baz())
# 0
# 1
# 2
# ...
# 9
・・・というのを考えついたのですが以下の理由で実際には使いませんでした
- 驚き最大
- たいてい後から普通に実装することになる
- 副作用を積極的に活用するのは気が引ける
- 言語に遊ばれてる気がして腹立ってきた
- ていうか今どきこんな低級API叩いてる人いないよ
というわけでどれだけ参考になるか知りませんがこれで終わります