asyncio等待对象 - 基本示例

时间:2017-06-28 19:03:58

标签: python python-asyncio

我正在努力了解如何制作一个等待的对象。来自documentation的定义:

  

使用__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())

我期待的流程是:

  1. 事件循环控制produce_list()produce_list()放弃了num = await Customer()
  2. 的执行
  3. Customer()被执行并返回一个迭代器。因为返回迭代器中的第一个值。 Q1: 这里不清楚为什么num没有成为迭代器本身。这也是send在这里做什么的?
  4. 一旦到达迭代器的最后一个值。 num = 4协程的执行继续print(num),并打印值4.
  5. 我得到了什么:

    ---------------------------------------------------------------------------
    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
    

    我在这里犯了什么概念?

    最后,我正在寻找一个示例,它使用列表中的迭代作为事件返回到协程的控制。

1 个答案:

答案 0 :(得分:5)

__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_atloop.add_readerloop.add_writerloop.add_signal_handler等。

  

asioio库,例如aiohttp。我假设有些代码不依赖于以前的协同程序的存在。

所有IO操作都必须最终委托给事件循环才能实现单线程并发。 例如,aiohttp依赖于loop.create_connection协程到manage the TCP connection