I have tried the following code in Python 3.6 for asyncio: Example 1:
我在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))
Output is as expected:
输出符合预期:
hello
hello
hello again
hello again
Then I want to change the asyncio.sleep into another def:
然后我想将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))
Output:
输出:
hello
hello again
hello
hello again
It seems it is not running in an asynchronous mode, but a normal sync mode.
它似乎不是以异步模式运行,而是以正常同步模式运行。
The question is: Why is it not running in an asynchronous mode and how can I change the old sync module into an 'async' one?
问题是:为什么它不以异步模式运行?如何将旧的同步模块更改为“异步”模块?
1 个解决方案
#1
7
Asyncio uses an event loop, which selects what coroutine in the queue to activate next. The event loop can make intelligent decisions as to what coroutine is ready to do actual work. This is why the event loop also is responsible for creating connections and watching file descriptors and other I/O primitives; it gives the event loop insight into when there are I/O operations in progress or when results are available to process.
Asyncio使用一个事件循环,它选择队列中的哪个协程接下来要激活。事件循环可以做出关于什么协程准备好做实际工作的明智决策。这就是为什么事件循环还负责创建连接和观察文件描述符和其他I / O原语;它使事件循环能够深入了解正在进行的I / O操作或何时可以处理结果。
Whenever you use await
, another coroutine is added to the event loop queue. Which coroutine then is picked for execution depends on the exact implementation; the asyncio
reference implementation offers multiple choices, but there are other implementations, such as the very, very efficient uvloop implementation.
无论何时使用await,都会在事件循环队列中添加另一个协程。然后选择执行哪个协程取决于具体实现; asyncio参考实现提供了多种选择,但还有其他实现,例如非常非常有效的uvloop实现。
Your sample is still asynchronous. It just so happens that by replacing the await.sleep()
with a synchronous time.sleep()
call, inside a new coroutine function, you introduced 2 coroutines into the queue that don't yield, and thus influenced in what order they are executed. That they are executed in what appears to be synchronous order is a coincidence. If you switched event loops, or introduced more coroutines (especially some that use I/O), the order can easily be different again.
您的示例仍然是异步的。只是通过用同步time.sleep()调用替换await.sleep(),在新的协同程序函数中,你将2个协同程序引入到队列中而不会产生,从而影响它们的顺序执行。它们以看似同步的顺序执行是巧合。如果您切换了事件循环,或者引入了更多协程(特别是那些使用I / O的协同程序),那么订单可能会再次变得不同。
Moreover, your new coroutines use time.sleep()
; this makes your coroutines uncooperative. The event loop is not notified that your code is waiting (time.sleep()
will not yield!), so no other coroutine can be executed while time.sleep()
is running. time.sleep()
simply doesn't return or lets any other code run until the requested amount of time has passed. Contrast this with the asyncio.sleep()
implementation, which simply yields to the event loop with a call_later()
hook; the event loop now knows that that coroutine won't need any attention until a later time.
而且,你的新协同程序使用time.sleep();这使你的协同不合作。事件循环不会通知您的代码正在等待(time.sleep()不会产生!),因此在time.sleep()运行时不能执行其他协程。 time.sleep()根本不返回或让任何其他代码运行,直到所请求的时间已过。将此与asyncio.sleep()实现进行对比,该实现只是通过call_later()钩子生成事件循环;事件循环现在知道该协程直到稍后才需要注意。
#1
7
Asyncio uses an event loop, which selects what coroutine in the queue to activate next. The event loop can make intelligent decisions as to what coroutine is ready to do actual work. This is why the event loop also is responsible for creating connections and watching file descriptors and other I/O primitives; it gives the event loop insight into when there are I/O operations in progress or when results are available to process.
Asyncio使用一个事件循环,它选择队列中的哪个协程接下来要激活。事件循环可以做出关于什么协程准备好做实际工作的明智决策。这就是为什么事件循环还负责创建连接和观察文件描述符和其他I / O原语;它使事件循环能够深入了解正在进行的I / O操作或何时可以处理结果。
Whenever you use await
, another coroutine is added to the event loop queue. Which coroutine then is picked for execution depends on the exact implementation; the asyncio
reference implementation offers multiple choices, but there are other implementations, such as the very, very efficient uvloop implementation.
无论何时使用await,都会在事件循环队列中添加另一个协程。然后选择执行哪个协程取决于具体实现; asyncio参考实现提供了多种选择,但还有其他实现,例如非常非常有效的uvloop实现。
Your sample is still asynchronous. It just so happens that by replacing the await.sleep()
with a synchronous time.sleep()
call, inside a new coroutine function, you introduced 2 coroutines into the queue that don't yield, and thus influenced in what order they are executed. That they are executed in what appears to be synchronous order is a coincidence. If you switched event loops, or introduced more coroutines (especially some that use I/O), the order can easily be different again.
您的示例仍然是异步的。只是通过用同步time.sleep()调用替换await.sleep(),在新的协同程序函数中,你将2个协同程序引入到队列中而不会产生,从而影响它们的顺序执行。它们以看似同步的顺序执行是巧合。如果您切换了事件循环,或者引入了更多协程(特别是那些使用I / O的协同程序),那么订单可能会再次变得不同。
Moreover, your new coroutines use time.sleep()
; this makes your coroutines uncooperative. The event loop is not notified that your code is waiting (time.sleep()
will not yield!), so no other coroutine can be executed while time.sleep()
is running. time.sleep()
simply doesn't return or lets any other code run until the requested amount of time has passed. Contrast this with the asyncio.sleep()
implementation, which simply yields to the event loop with a call_later()
hook; the event loop now knows that that coroutine won't need any attention until a later time.
而且,你的新协同程序使用time.sleep();这使你的协同不合作。事件循环不会通知您的代码正在等待(time.sleep()不会产生!),因此在time.sleep()运行时不能执行其他协程。 time.sleep()根本不返回或让任何其他代码运行,直到所请求的时间已过。将此与asyncio.sleep()实现进行对比,该实现只是通过call_later()钩子生成事件循环;事件循环现在知道该协程直到稍后才需要注意。