我是 asyncio 的新手,正在尝试了解它的实际工作原理。
假设我们有两个协程,其中一个看起来像这样:
async def f():
await sleep(10)
print('something')
显然,sleep()
可以是任何 IO 操作。
如果我对这段代码的理解正确,我们将开始执行 sleep(10)
并将上下文切换到其他一些协程(如果存在)。
但是如果这个协程被挂起,解释器如何“计算”那 10 秒呢?或者解释器如何处理某些 IO 响应,如果它发生在协程挂起时?
最佳答案
在内部 asyncio.sleep()
返回一个 Future
对象。
future 的值(value)将在超时到期后设置。
每个 coroutine 都由 asyncio.Task
执行。 future 冒泡到任务运行器(Task._step()
实际上)。
运行者向冒泡的 future 添加一个回调,以便在未来完成时唤醒自己。
sleep()
实现很简单:
@coroutine
def sleep(delay, result=None, *, loop=None):
"""Coroutine that completes after a given time (in seconds)."""
if delay == 0:
yield
return result
if loop is None:
loop = events.get_event_loop()
future = loop.create_future()
h = future._loop.call_later(delay,
futures._set_result_unless_cancelled,
future, result)
try:
return (yield from future)
finally:
h.cancel()
任务运行器要复杂得多,但它的源代码仍然可读:https://github.com/python/asyncio/blob/master/asyncio/tasks.py#L223-L300
每个阻塞 IO 也会返回一个 future (可能来自非常深的内部调用)。当 IO 等待完成时,给定值(或异常)被分配给 future ,任务运行器被唤醒并恢复挂起的协程。
关于python 3.5 asyncio 解释器如何处理 'suspended' 协程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40799981/