解決済みですが、応用的な話題で
以下コード#(1), #(2)はあっても無くても挙動は変わりません。
接続が成功しなかった場合の、実際の挙動が変わります。
作用が判り難いのは、main -> ws_connect -> coro だと「直列」な呼び出しで、
~の完了後に処理したいだけなら await した後にコード書けば同じだったり、
もしくは、add_done_callback で後処理を登録したりもできます。
(違い・使い分けは、コードのスコープだったり例外時やキャンセル時の挙動)
非同期処理においては、 双方の関数のスコープを継続したまま 、
待ち合わせする為の同期機構として使えます。
質問のコードのケースでも、有効な使い道はあり
python
1# 接続成功後に event.set() されているので
2# 接続に成功する迄の時間のタイムアウト
3await asyncio.wait_for(event.wait(), timeout=10)
4
5# イベントによる通知がないと
6# タスク全体のタイムアウト(タイムアウト時の、接続成功の合否はわからない)
7await asyncio.wait_for(task, timeout=10)
通常の、同期コードでは、失敗時は例外を出して中断することになりますが、
asyncio等のイベント駆動では、例外の捕捉を呼び出し元からは、
対象のコルーチン(を含むタスク)を直接 await する迄できません。
python
1# asyncio での例外の扱い
2await task1 # この間(task1完了前)に task2 内部で例外が起きても
3await task2 # task2 からの例外が発生するのは、コード上ではこちら
どのようなケースで活用するかの解としては、
「コルーチン間でイベントを通知する手段」として使うことが出来ます。
同期プリミティブは、同期処理を実現するための手段の一つなので、
アイデア次第で他にも様々な用途で使うことが出来ます。
python
1async def process(event):
2 for num in range(100):
3 await event.wait()
4 print(f"{num=}")
5
6# 外部からの操作で event set()/clear() で、一時停止・再開
- 任意のタイミングでキャンセル可能な sleep の実装
(wait_for と組み合わせてタイムアウト処理)
python
1async def past(event, within):
2 """
3 Examples
4 --------
5
6 if await past(event, within=10):
7 ... # 10 秒以内に event.set() が呼ばれた。
8 else:
9 ... # 10 秒以上経過。タイムアウト時
10 """
11 try:
12 await asyncio.wait_for(event.wait(), timeout=within)
13 except asyncio.TimeoutError:
14 pass
15 # NOTE: マルチスレッドではないので、
16 # この間に await がない限り event.set() が呼ばれることはない
17 return event.is_set()
18
参考までに、マルチプロセスやマルチスレッドでも同樣のクラス群が提供されており、
同期プリミティブは、独自の同期機構を作るための部品として扱われます。
より具体的な応用例は:「同期」や「排他制御」辺りの用語がヒント。
例えば、独自の sleep を Event を使って実装する場合、
n秒後に event.set が呼ばれるように設定された event として実装できます。
python
1async def my_sleep(delay):
2 # NOTE: event を引数で与えるようにすれば、外部からも中断可能に。
3
4 event = asyncio.Event()
5 loop = asyncio.get_running_loop()
6
7 if delay <= 0:
8 loop.call_soon(event.set)
9 else:
10 loop.call_later(delay, event.set)
11 await event.wait()
※用例を示すもので、実際の asyncio.sleep の実装では有りません。
実際の asyncio.Event, asyncio.sleep は、どちらも より低階層の API future で実装されてます。
存在意義としては、他の言語・ライブラリでも同樣の概念が確立されているので、
「車輪の再発明」を避ける為にも有用です。Pythonのライブラリ内でも
threading.Event, multiprocessing.Event に同じインターフェースを持つクラスがあり、
それぞれ スレッド間、プロセス間、で同樣の役割を果たします。
asyncio.Event は、それらに対して コルーチン間でのイベント通知・同期機構を提供します。
⇛ マルチスレッド・マルチプロセスのコードを asyncio へ移植する際に、
共通の部品が使えると便利。他の部品は、Lock や Queue 等。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/06/22 00:46