Open5
pythonのコルーチン的なものを試したい
例えばサーバに重めの処理を投げて待つだけ、という処理を並列して行うクライアントを書くときに、スレッドは要求する機能として強すぎる気がするので、JavaScriptのように非同期タスクを積む感じで実行できないかと探したら
を見つけたのでちょっと触ってみたい。Goのgoroutine的なものだといいな。
とりあえずhello worldを動かす。
import asyncio
async def main():
print('hello')
await asyncio.sleep(1)
print('world')
asyncio.run(main())
async functionの外でawaitを使おうとするとエラーになる。
asataka@tailmoon hello-python % ./main.py
File "/Users/asataka/src/local/hello-python/./main.py", line 6
await asyncio.sleep(1)
^^^^^^^^^^^^^^^^^^^^^^
SyntaxError: 'await' outside async function
asataka@tailmoon hello-python %
sleepの代わりにasyncio.sleepを使うのは普通のsleepだとブロッキングになるからなのかな。
以下のような書き方をしたときに並列で実行されるのはmain3だけになる。
async def say_after(delay: int, what: str):
await asyncio.sleep(delay)
print(what)
async def main1():
await say_after(1, 'hello')
await say_after(2, 'world')
async def main2():
await asyncio.create_task(say_after(1, 'hello'))
await asyncio.create_task(say_after(2, 'world'))
async def main3():
task1 = asyncio.create_task(say_after(1, 'hello'))
task2 = asyncio.create_task(say_after(2, 'world'))
await task1
await task2
REPLで動かしながら何が返ってきているのか確認してみる。
asyncは構文だけどasyncioはパッケージなのがちょっとややこしいかもしれない。
async def say_after(delay: int, what: str):
await asyncio.sleep(delay)
print(what)
say_after(1, 'hello')
# <coroutine object say_after at 0x10bf43300>
import asyncio
asyncio.create_task(say_after(1, 'hello'))
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# File "/Users/asataka/.asdf/installs/python/3.10.1/lib/python3.10/asyncio/tasks.py", line 336, in create_task
# loop = events.get_running_loop()
# RuntimeError: no running event loop
async functionを呼び出すとcoroutine objectというものが返ってくるらしい。
asyncio.create_taskをするとno running event loopとエラーが出るので、多分REPL環境では実行できないんだろう。