TL;DR
Tornadoのioloop
を使うと非同期タイマもどきが作れるので,手軽にマルチタスクっぽいことが実現出来る.
多分threading
を使うより手軽.
なにがしたいか
一定周期に実行されるタスクを複数平行して走らせたい.
やり方
tornadoのIOLoop
クラスを使うと簡単に非同期ループが実現出来ます.
IOLoop
はtornadoでプロセスごとに(多分)一つずつ生成されるイベントループで,いい感じに非同期処理をやってくれます.
IOLoop
はプロセスにつき一つずつなので,ソース全体で使い回す必要があります.
tornado.ioloop.IOLoop.current()
を呼ぶことで,今使うべきIOLoop
クラスのインスタンスが帰って来るのでこれを使いましょう.
インスタンスに対してadd_timeout(deadline, callback)
で時間と関数を設定してあげると,時刻がdeadline
をすぎた時に,callback
が実行されます.
例
# -*- coding: utf-8 -*-
import time
import tornado.ioloop
def loop1():
PERIOD = 2
ioloop = tornado.ioloop.IOLoop.current()
ioloop.add_timeout(time.time() + PERIOD, loop1)
print("loop1")
# 実際の処理はこの辺に書く(その1)
def loop2():
PERIOD = 0.5
ioloop = tornado.ioloop.IOLoop.current()
ioloop.add_timeout(time.time() + PERIOD, loop2)
print("loop2")
# 実際の処理はこの辺に書く(その2)
if __name__ == "__main__":
loop1()
loop2()
tornado.ioloop.IOLoop.current().start()
print("Ooops!") # ←実行されない
ループを二つ並列に走らせる例です.
loop1
は2秒ごと,loop2
は0.5秒ごとに実行されるので実行結果は
loop1
loop2
loop2
loop2
loop2
loop1
loop2
loop2
loop2
loop2
(以下略
のようにloop1
が1回実行される間に,loop2
が4回実行されています.
なお,一度loop1()
とloop2()
を呼ぶだけだと,IOLoop
クラスに登録されるだけで実際にループが走り出さないのでtornado.ioloop.IOLoop.current().start()
を呼んでループをスタートさせる必要があります.
一度ループがスタートすると,それ以降の処理は実行されないため最後の行のprint("Ooops!") # ←実行されない
はコメント通り実行されないようです.
要は,add_timeout
にコールバック関数が登録さえ出来れば良いのでメンバ関数であろうと無かろうと簡単に並列化ができます.
加えてかなりシンプルなソースで並列化が実現できるのでお勧めです.