きっかけ
asyncio
の良さげなサンプルコードがなかったのですが、Python でのオンデマンド・データ, 第 3 回 コルーチンと asyncioがレストランにいるウェイターが複数のオーダーに対応するといったより具体的なストーリーを交えて説明していたので一番分かりやすくて参考になります。
よく見かけるpython3 の async/awaitを理解するやPythonにおける非同期処理: asyncio逆引きリファレンスよりも良いです。
開発
import asyncio
import time
async def start_time(src):
await asyncio.sleep(src)
print("START!!!")
async def main_process(span):
idx = 1
while True:
await asyncio.sleep(span)
num_active_tasks = len([ task for task in asyncio.Task.all_tasks(loop) if not task.done()])
if num_active_tasks == 1:
break
print("[run:{}]{}秒経過".format(num_active_tasks, idx * span))
idx += 1
async def end_time(src):
await asyncio.sleep(src)
print("END!!!")
if __name__ == "__main__":
loop = asyncio.get_event_loop()
try:
loop.run_until_complete(
asyncio.gather(
start_time(10),
main_process(1),
end_time(20)
)
)
finally:
loop.close()
注目点は
len([ task for task in asyncio.Task.all_tasks(loop) if not task.done()])
で asyncio.Task.all_tasks(loop) if not task.done()
とすることで現在常駐しているタスクを取得することができます。
結果
出力結果は下記の通りです。
メイン処理のみ起動している場合はloopから抜けています。
[run:3]1秒経過
[run:3]2秒経過
[run:3]3秒経過
[run:3]4秒経過
[run:3]5秒経過
[run:3]6秒経過
[run:3]7秒経過
[run:3]8秒経過
[run:3]9秒経過
START!!!
[run:2]10秒経過
[run:2]11秒経過
[run:2]12秒経過
[run:2]13秒経過
[run:2]14秒経過
[run:2]15秒経過
[run:2]16秒経過
[run:2]17秒経過
[run:2]18秒経過
[run:2]19秒経過
END!!!
おわりに
asyncio.Task.all_tasks()
ですが Python3.7 以降では非推奨で3.9では削除されるとのことです。特にasyncio
の部分でversionが上がるごとに書き方がかなり様変わりしそうです。
(Python3.8 doc Task オブジェクト を参照)