はじめに
- 最近非同期処理について触れることがあり、pythonのasync/awaitについて調べてみた。
- 深掘ろうとすると、抜けなくなりそうなので、簡単な実装で終える。
非同期処理とは
- 処理Aと処理Bを同時に実行できる
- 並行処理
- 同期処理(逐次処理)の逆の意味の言葉
- 非同期処理を使う場面は、「処理の完了まで時間がかかる」場合
- pythonではI/Oバウンド(入出力における負荷)の軽減ために用いられる。
- ファイルの読み書き
- DBの読み書き
asyncio 非同期I/O
asyncio は async/await 構文を使い 並行処理の コードを書くためのライブラリです。
asyncio は、高性能なネットワークとウェブサーバ、データベース接続ライブラリ、分散タスクキューなどの複数の非同期 Python フレームワークの基盤として使われています
asyncioを使った実装1
まず使ってみる。(非同期処理ではない)
import asyncio
import time
async def main():
print(f"Start : {time.strftime('%X')}")
await asyncio.sleep(3)
print(f"Rest : {time.strftime('%X')}")
await asyncio.sleep(1)
print(f"End : {time.strftime('%X')}")
if __name__ == "__main__":
asyncio.run(main())
❯❯❯ python async_test.py
Start : 22:51:19
Rest : 22:51:22
End : 22:51:23 #合計6秒なので、これは同期処理。
(memo) コルーチン(asynic
をつける)にawait
をつけるとコルーチンが実行されて処理が終わるまで待つになる。
関数を使って実装してみる。
async def function(wait_sec):
await asyncio.sleep(wait_sec)
return f"Wait for {wait_sec} sec."
async def main():
print(f"Start : {time.strftime('%X')}")
results_1 = await function(2)
print(results_1)
print(f"Rest : {time.strftime('%X')}")
results_2 = await function(4)
print(results_2)
print(f"End : {time.strftime('%X')}")
if __name__ == "__main__":
asyncio.run(main())
❯❯❯ python async_test.py
Start : 22:59:52
Wait for 2 sec.
Rest : 22:59:54
Wait for 4 sec.
End : 22:59:58 #合計6秒なので、これは同期処理。
(memo) コルーチンの処理を関数として切り出したら、関数の前にawait
をつける必要がある。(なんか変な感じだ...)
asyncioを使った実装2
非同期処理を実装する。async.create_task
を利用する。
async def main():
print(f"Start : {time.strftime('%X')}")
task1 = asyncio.create_task(function(2))
task2 = asyncio.create_task(function(4))
await task1
await task2
print(task1.result())
print(task2.result())
print(f"End : {time.strftime('%X')}")
if __name__ == "__main__":
asyncio.run(main())
❯❯❯ python async_test.py
Start : 23:05:09
Wait for 2 sec.
Wait for 4 sec.
End : 23:05:13 #合計4秒なので、これは非同期処理!!
できた。
おわりに
- 非同期処理の奥は深く、
gather
,await future
,await coroutine
,run_in_executor
,wait_for
など、扱えたら扱いたい。 - コルーチン とは 「いったん処理を中断した後、続きから処理を再開できるプログラミングの構造。」
コルーチン(英: co-routine)とはプログラミングの構造の一種。サブルーチンがエントリーからリターンまでを一つの処理単位とするのに対し、コルーチンはいったん処理を中断した後、続きから処理を再開できる。接頭辞 co は協調を意味するが、複数のコルーチンが中断・継続により協調動作を行うことによる。
サブルーチンと異なり、状態管理を意識せずに行えるため、協調的処理、イテレータ、無限リスト、パイプなど、継続状況を持つプログラムが容易に記述できる。
(参考wiki)