待ちに待ったオブジェクトの作り方を理解しようとしています。 ドキュメント からの定義は次のように述べています。
イテレータを返す__await__メソッドを持つオブジェクト。
その定義に基づいて、サンプルコードを作成しました。
_import asyncio
async def produce_list():
num = await Customer()
print(num)
class Customer(object):
def __await__(self):
return iter([1, 2, 3, 4])
loop = asyncio.get_event_loop()
loop.run_until_complete(produce_list())
_
私が期待した流れは次のとおりです。
produce_list()
を制御します。 produce_list()
はnum = await Customer()
の実行を断念します。Customer()
が実行され、イテレータを返します。これは、イテレータの最初の値を返すためです。 Q1:ここでは理由が明確ではありませんnum
イテレータ自体にはなりません。また、ここでsend
を実行しているのは何ですか?num = 4
_コルーチンの実行はprint(num)
に続き、値4を出力します。私が得たもの:
_---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
~/workspace/dashboard/so_question_await.py in <module>()
16
17 loop = asyncio.get_event_loop()
---> 18 loop.run_until_complete(produce_list())
/usr/lib/python3.5/asyncio/base_events.py in run_until_complete(self, future)
464 raise RuntimeError('Event loop stopped before Future completed.')
465
--> 466 return future.result()
467
468 def stop(self):
/usr/lib/python3.5/asyncio/futures.py in result(self)
291 self._tb_logger = None
292 if self._exception is not None:
--> 293 raise self._exception
294 return self._result
295
/usr/lib/python3.5/asyncio/tasks.py in _step(***failed resolving arguments***)
239 result = coro.send(None)
240 else:
--> 241 result = coro.throw(exc)
242 except StopIteration as exc:
243 self.set_result(exc.value)
~/workspace/dashboard/so_question_await.py in produce_list()
5
6 async def produce_list():
----> 7 num = await Customer()
8 print(num)
9
RuntimeError: Task got bad yield: 1
_
ここで間違った概念は何ですか?
最後に、コルーチンの制御に戻るためのイベントとしてリストの反復を使用する例を探しています。
___await__
_は、コルーチンの基礎となるメカニズムが元々_yield from
_構文に基づいているため、イテレーターを返します。実際には、___await__
_はiter(some_future)
またはsome_coroutine.__await__()
のいずれかを返します。待機するたびに異なる値を生成するオブジェクトを作成するために使用できます。この簡単な例を参照してください。
_import asyncio
import random
class RandomProducer:
def __await__(self):
return self.producer().__await__()
async def producer(self):
sleep = random.random()
value = random.randint(0, 9)
return await asyncio.sleep(sleep, result=value)
async def main():
producer = RandomProducer()
while True:
print(await producer)
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
_
あなたのコメントに答えるために:
すべてのコルーチンは最終的に_
asyncio.sleep
_を呼び出すことになりますか?
いいえ、_asyncio.sleep
_は実際にはチェーンの終わりではありません。一番下にあるのは、常に未来が生み出されていることです。コルーチンチェーンは、イベントループに「この未来が結果をもたらしたら、私を起こしてください」と尋ねます。 _asyncio.sleep
_の場合、_loop.call_later
_を使用して、指定された時間が経過した後の将来の結果を設定します。ループは、コールバックをスケジュールするためのより多くのメソッドを提供します:_loop.call_at
_、_loop.add_reader
_、_loop.add_writer
_、_loop.add_signal_handler
_など。
Aiohttpなどの非同期ライブラリ。以前のコルーチンの存在に依存しないコードがどこかにあると思います。
シングルスレッドの同時実行性を実現するには、すべてのIO操作をイベントループに委任する必要があります。たとえば、aiohttpは loop.create_connection コルーチンに依存しています。 TCP接続 を管理します。