Future的对象如何在Python的asyncio中使用?

时间:2018-05-07 16:09:40

标签: python python-asyncio

我理解了事件循环的基本思想。有一个中央循环监听一组文件描述符,如果它已准备好进行读或写,则执行相应的回调。

我们可以使用共同例程而不是回调,因为它们可以暂停和恢复。但是,这意味着在协同例程和事件循环之间应该有一些通信协议,以使事情正常工作?

我编写了一个带有协同例程的简单Echo Server,它会产生fd以及感兴趣的动作,如yield fd, 'read'yield fd, 'write'等,然后事件循环将注册{{1}因此。回调将是恢复协同例程。它工作正常,我已添加下面的代码。

现在我只想了解select实际上是如何运作的。它似乎不会像我的示例代码那样产生fds和相应的动作,相反,它会为你提供一个await对象。那么引擎盖下究竟发生了什么呢?它是如何与事件循环通信的?

我的猜测是Future会像这样执行:

  1. 事件循环将执行协同例程并到达await async.sleep(1)
  2. 它将创建一个async.sleep(1)对象。
  3. 然后它会创建一个fd,可能会使用带有回调的Future来完成timerfd_create
  4. 然后将其提交给事件循环进行监控。
  5. Future会将await对象生成到正在执行它的事件循环。
  6. 事件循环会将Future对象的回调函数设置为仅恢复协程。
  7. 我的意思是我可以像这样使用Future。但这是真的发生了什么?有人能帮助我更好地理解这一点吗?

    PS:Future仅作为示例,因为我无法理解如何在事件循环中实现定时器。对于这个问题的目的,网络fds也是如此。如果有人可以帮助我实现计时器的实现方式,那就太好了!

    以下是使用协同例程的简单Echo Server的实现:

    timerfd_create

1 个答案:

答案 0 :(得分:1)

  

我编写了一个带有协同例程的简单Echo Server,它会产生fd以及感兴趣的动作,如yield fd, 'read'yield fd, 'write'等,然后事件循环将注册{{1}相应的。

这类似于Dave Beazley的curio的工作原理。要了解有关该概念的更多信息,请参阅此lecture,其中从基础知识构建事件循环。 (他使用3.5之前的select语法,但它与yield from完全相同。)

正如您所发现的那样,尽管原理仍然相似,但asyncio的工作方式略有不同。

  

现在我只想了解await实际上是如何运作的。它似乎没有产生fds,并且字符串对应于上面示例中的操作,而是它为您提供了一个await对象。那么引擎盖下究竟发生了什么呢?它是如何与事件循环通信的?

简短版本是阻塞协同程序使用全局变量(通过Future)来获取事件循环。事件循环具有调度在发生有趣事件时调用的回调的方法。 asyncio.get_event_loop() calls asyncio.sleep确保在超时时间后恢复。

产生的loop.call_later只是一种方便的方式,可以在事件循环就绪后通知结果,以便它可以正确地恢复Future(协程驱动)通过事件循环)等待阻塞操作,同时还处理异常和取消。有关Task.__step的信息,请参见the gory details

  

Task仅作为示例,因为我无法理解如何在事件循环中实现计时器。

实现定时器,以便事件循环跟踪文件描述符和超时,并issues a selectearliest timeout过去时终止。 Dave的上述讲座简洁地展示了这一概念。