0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

asyncioのawaitとcoroutine実行を理解する

0
Last updated at Posted at 2022-09-15

awaitはcoroutineの処理が完了するまで待つ。
複数のcoroutineを並列に走らせるにはasyncio.gatherを使うのだが、複数のcoroutineを並べてawaitするとどうなるのか。

まずはgather。

python main.py
import asyncio
import time

async def func(sleep):
    print(f"{int(time.time())} func start sleep:{sleep}")
    await asyncio.sleep(sleep)
    print(f"{int(time.time())} func end sleep:{sleep}")

async def main():
    print(f"{int(time.time())} main start")
    sleep_task1 = asyncio.create_task(func(sleep=1))
    sleep_task2 = asyncio.create_task(func(sleep=2))
    await asyncio.gather(sleep_task1, sleep_task2)
    print(f"{int(time.time())} main end")

asyncio.run(main())
output.log
1663209464 main start
1663209464 func start sleep:1
1663209464 func start sleep:2
1663209465 func end sleep:1
1663209466 func end sleep:2
1663209466 main end

全てのcoroutineが並列に実行され、完了するまで(つまりsleep_task2が完了するまで)待っている.

ではawaitを並べてみる。mainを書き換える.

async def main():
    print(f"{int(time.time())} main start")
    sleep_task1 = asyncio.create_task(func(sleep=1))
    sleep_task2 = asyncio.create_task(func(sleep=2))
    await sleep_task1
    await sleep_task2
    print(f"{int(time.time())} main end")
output.log
1663209617 main start
1663209617 func start sleep:1
1663209617 func start sleep:2
1663209618 func end sleep:1
1663209619 func end sleep:2
1663209619 main end

なんとなく、sleep_task1の完了を待ってからsleep_task2を開始するのかなと思ってたが、gatherを使った場合と変わらない。並列に開始し、sleep_task2が完了するまで待っているようだ。

ではこうするとどうなるのか

async def main():
    print(f"{int(time.time())} main start")
    sleep_task1 = asyncio.create_task(func(sleep=1))
    await sleep_task1 # create_taskの間に挟む.
    sleep_task2 = asyncio.create_task(func(sleep=2))
    await sleep_task2
    print(f"{int(time.time())} main end")
output.log
1663209991 main start
1663209991 func start sleep:1
1663209992 func end sleep:1
1663209992 func start sleep:2
1663209994 func end sleep:2
1663209994 main end

この場合はsleep_task1の完了を待ってからsleep_task2を開始し、完了を待っている.
awaitは、awaitを実行した段階でasyncio.create_taskによりスケジュールされているcoroutineのみを実行開始し、完了を待つようだ。

では2つのcoroutineをasyncio.create_taskでスケジュールするが、awaitを1つしかしない場合どうなるのか.

async def main():
    print(f"{int(time.time())} main start")
    sleep_task1 = asyncio.create_task(func(sleep=1))
    sleep_task2 = asyncio.create_task(func(sleep=2))
    await sleep_task1
    # await sleep_task2 # sleep_task2はawaitしない.
    print(f"{int(time.time())} main end")
output.log
1663210406 main start
1663210406 func start sleep:1
1663210406 func start sleep:2
1663210407 func end sleep:1
1663210407 main end

こちらはなんとなくsleep_task2は実行されないのではと思ってしまうが、sleep_task1sleep_task2は並列に開始されている。だが、awaitしていないsleep_task2は完了しないままプロセスが終了している.

awaitを実行すると処理が走るので、awaitは「指定されたcoroutineを実行し、完了まで待つ」という認識を持ってしまうがそうではなく、awaitはあくまで「指定されたcoroutineの完了を待つ」。
実行されるcoroutineはawaitするまでにスケジュールしたcoroutineである。
そしてawaitしていないcoroutineは実行されても当然完了を待たない。

まとめ

  • awaitを実行した時、それまでにcreate_taskでスケジュールされたcoroutineが実行される。
  • awaitはあくまで待つsynctaxである。開始する処理を指定するものではない。
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?