Python协同程序

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必须是一个发电机(因为它是一个协程).这个论点递归地适用.

我无法理解这个想法,在某些时候,这个过程只需要坐下来等待.

Mar*_*ers 6

这里的秘诀就是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版本).

请注意,未来不使用awaityield 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()继续,等等.