首页 文章

asyncio模块如何工作,为什么我的更新样本同步运行?

提问于
浏览
2

我在Python 3.6中尝试了以下用于asyncio的代码:示例1:

import asyncio
import time

async def hello():

    print('hello')
    await asyncio.sleep(1)
    print('hello again')

tasks=[hello(),hello()]    
loop=asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))

输出符合预期:

hello
hello
hello again
hello again

然后我想将asyncio.sleep更改为另一个def:

async def sleep():
    time.sleep(1)

async def hello():

    print('hello')
    await sleep()
    print('hello again')


tasks=[hello(),hello()]    
loop=asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))

输出:

hello
hello again
hello
hello again

它似乎不是以异步模式运行,而是以正常同步模式运行 .

问题是:为什么它不以异步模式运行?如何将旧的同步模块更改为“异步”模块?

1 回答

  • 8

    Asyncio使用一个事件循环,它选择队列中要激活的任务(协同程序的独立调用链) . 事件循环可以做出关于哪些任务准备好进行实际工作的明智决策 . 这就是为什么事件循环还负责creating connectionswatching file descriptors以及其他I / O原语;它使事件循环能够深入了解正在进行的I / O操作或何时可以处理结果 .

    无论何时使用 await ,都有机会将控制权返回给循环,然后可以将控制权传递给另一个任务 . 然后选择执行哪个任务取决于具体的实现; asyncio 参考实现offers multiple choices,但还有其他实现,例如非常非常高效的uvloop implementation .

    您的示例仍然是异步的 . 只是通过在同步 time.sleep() 调用中替换 await.sleep() ,在新的协同程序函数中,您将2个协同程序引入任务调用链中而不会产生,从而影响它们的执行顺序 . 它们以看似同步的顺序执行是巧合 . 如果您切换了事件循环,或者引入了更多协程(特别是那些使用I / O的协同程序),那么订单可能会再次变得不同 .

    此外,你的新协同程序使用 time.sleep() ;这使你的协同不合作 . 事件循环未通知您的代码正在等待( time.sleep() 将不会产生!),因此在 time.sleep() 运行时不能执行其他协程 . time.sleep() 只是在请求的时间过去之前不会返回或让任何其他代码运行 . 将此与asyncio.sleep() implementation进行对比,后者只需使用call_later() hook生成事件循环;事件循环现在知道该任务直到稍后才需要注意 .

    另请参阅asyncio: why isn't it non-blocking by default以更深入地讨论任务和事件循环如何交互 . 如果您必须运行无法协作的阻塞,同步代码,则使用executor pool在单独的胎面或子进程中执行阻止代码,以释放事件循环以执行其他更好的任务 .

相关问题