Pau*_*aul 5 python asynchronous async-await
我对Javascript中的promises有一点经验.我对Python非常有经验,但对于它的协同程序来说是新手,有一点我不明白:异步性在哪里开始?
让我们考虑以下最小的例子:
async def gen():
await something
return 42
Run Code Online (Sandbox Code Playgroud)
据我所知,await something将我们的函数执行放在一边,让主程序运行其他位.在某些时候something有一个新的结果,gen很快就会有结果.
如果gen并且something是协同程序,那么通过所有的互联网智慧,他们是发电机.通过轮询,了解发电机何时可以使用新物品的唯一方法是:x=gen(); next(x).但这是阻止!调度程序如何"知道"何时x有结果?答案不能是"什么时候something有结果"因为something必须是一个发电机(因为它是一个协程).这个论点递归地适用.
我无法理解这个想法,在某些时候,这个过程只需要坐下来等待.
这里的秘诀就是asyncio模块.你的something对象本身必须是一个等待的对象,要么依赖于更多等待的对象,要么必须从Future对象中产生.
例如,asyncio.sleep()协程产生一个Future:
@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()
Run Code Online (Sandbox Code Playgroud)
(此处的语法使用较旧的生成器语法,以保持向后兼容较旧的Python 3版本).
请注意,未来不使用await或yield from; 他们只是使用,yield self直到满足某些条件.在上面的async.sleep()协同程序中,当产生结果时(在async.sleep()上面的代码中,通过futures._set_result_unless_cancelled()延迟后调用的函数)满足该条件.
然后事件循环继续从它管理的每个待处理的未来(有效地轮询它们)中拉入下一个"结果",直到将来发出信号(通过提出StopIteration保存结果的异常; return来自协同例程会这样做,例如).在那时,产生未来的协程可以被发信号通知(通过发送未来结果,或者如果未来提出任何其他内容则抛出异常StopIteration).
因此,对于您的示例,循环将启动您的gen()协程,await something然后(直接或间接)产生未来.对该未来进行轮询,直到它提出StopIteration(发出信号)或引发其他一些例外.如果未来完成,coroutine.send(result)则执行,然后允许它前进到该return 42行,触发StopIteration具有该值的新异常,允许等待的呼叫协同程序gen()继续,等等.