昨日の asyncio 続きです。
振り返り
昨日は、非同期なメソッド を asyncio.create_task でタスク化して並列実行しました。
import asyncio import time async def say_after(msg: str, delay: int) -> str: print(f'{delay}秒後にメッセージを出力します') await asyncio.sleep(delay) print(msg) return f'{delay}秒後に「{msg}」を出力しました' async def main(): task1 = asyncio.create_task(say_after("Hello", 10)) task2 = asyncio.create_task(say_after("World", 5)) a = await task1 b = await task2 print("Result:", a) print("Result:", b) if __name__ == '__main__': asyncio.run(main())
本題
元々同期的な処理を非同期で実施するには どうしたらよいでしょうか?
おそらく、別スレッドで処理させる必要がある と思います。
say_after が同期メソッドだった場合にどうやるのか?
asyncio でのやり方
say_after が以下のような状態のときです
import time def say_after(msg: str, delay: int) -> str: print(f'{delay}秒後にメッセージを出力します') time.sleep(delay) print(msg) return f'{delay}秒後に「{msg}」を出力しました'
main は以下のようにすると非同期で実施できるようです
import asyncio from datetime import datetime from zoneinfo import ZoneInfo async def main(): start_datetime = datetime.now(ZoneInfo("Asia/Tokyo")) print(f"ENTER(main) : {start_datetime.isoformat()}") loop = asyncio.get_running_loop() task1 = loop.run_in_executor(None, say_after, "Hello", 10) task2 = loop.run_in_executor(None, say_after, "World", 5) b = await task2 a = await task1 print("Result:", a) print("Result:", b) end_datetime = datetime.now(ZoneInfo("Asia/Tokyo")) print(f"EXIT(main) : {end_datetime.isoformat()} : Elapsed Time: {round(end_datetime.timestamp() - start_datetime.timestamp(), 2)}") if __name__ == '__main__': print(f"START : main()") asyncio.run(main()) print(f"END : main()")
ログも出力するので非同期実施以外のコードもありますが・・・
実行結果
$ python app.py START : main() ENTER(main) : 2024-09-13T22:19:54.690412+09:00 10秒後にメッセージを出力します 5秒後にメッセージを出力します World Hello Result: 10秒後に「Hello」を出力しました Result: 5秒後に「World」を出力しました EXIT(main) : 2024-09-13T22:20:04.704484+09:00 : Elapsed Time: 10.01 END : main()
5秒後に「World」の文字が出力され、10秒後に「Hello」の文字が出力されました
time.sleep()
を使っていますが、ちゃんと5秒と10秒の停止処理が非同期で動いています
まとめ
比較的簡単に非同期処理ができることがわかった