我理解了事件循环的基本思想。有一个中央循环监听一组文件描述符,如果它已准备好进行读或写,则执行相应的回调。
我们可以使用共同例程而不是回调,因为它们可以暂停和恢复。但是,这意味着在协同例程和事件循环之间应该有一些通信协议,以使事情正常工作?
我编写了一个带有协同例程的简单Echo Server,它会产生fd以及感兴趣的动作,如yield fd, 'read'
,yield fd, 'write'
等,然后事件循环将注册{{1}因此。回调将是恢复协同例程。它工作正常,我已添加下面的代码。
现在我只想了解select
实际上是如何运作的。它似乎不会像我的示例代码那样产生fds和相应的动作,相反,它会为你提供一个await
对象。那么引擎盖下究竟发生了什么呢?它是如何与事件循环通信的?
我的猜测是Future
会像这样执行:
await async.sleep(1)
。async.sleep(1)
对象。Future
来完成timerfd_create
。Future
会将await
对象生成到正在执行它的事件循环。Future
对象的回调函数设置为仅恢复协程。我的意思是我可以像这样使用Future
。但这是真的发生了什么?有人能帮助我更好地理解这一点吗?
PS:Future
仅作为示例,因为我无法理解如何在事件循环中实现定时器。对于这个问题的目的,网络fds也是如此。如果有人可以帮助我实现计时器的实现方式,那就太好了!
以下是使用协同例程的简单Echo Server的实现:
timerfd_create
答案 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 select
在earliest timeout过去时终止。 Dave的上述讲座简洁地展示了这一概念。