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

use*_*694 2 python async-await python-asyncio

我在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))
Run Code Online (Sandbox Code Playgroud)

输出符合预期:

hello
hello
hello again
hello again
Run Code Online (Sandbox Code Playgroud)

然后我想将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))
Run Code Online (Sandbox Code Playgroud)

输出:

hello
hello again
hello
hello again
Run Code Online (Sandbox Code Playgroud)

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

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

Mar*_*ers 10

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

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

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

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

另请参阅asyncio:为什么不是默认情况下非阻塞,以便更深入地讨论任务和事件循环如何交互.如果您必须运行阻止,无法进行协作的同步代码,则使用执行程序池在单独的步骤或子进程中执行阻塞代码,以释放事件循环以执行其他更好的任务.