所以我运行一个asyncio示例:
import asyncio, time
async def say_after(delay, what):
await asyncio.sleep(delay)
print(what)
async def main():
task1 = asyncio.create_task(say_after(1, 'hello'))
task2 = asyncio.create_task(say_after(2, 'world'))
print(f"started at {time.strftime('%X')}")
# Wait until both tasks are completed (should take
# around 2 seconds.)
await task1
await task2
print(f"finished at {time.strftime('%X')}")
asyncio.run(main())
这段代码与输出正确工作:
started at 14:36:06
hello
world
finished at 14:36:08
2个协程异步运行,最后花了2秒,没有问题。然而,当我合并将这些行组合在一起并直接等待Task对象时,如下所示:
import asyncio, time
async def say_after(delay, what):
await asyncio.sleep(delay)
print(what)
async def main():
print(f"started at {time.strftime('%X')}")
# Wait until both tasks are completed (should take
# around 2 seconds.)
await asyncio.create_task(say_after(1, 'hello'))
await asyncio.create_task(say_after(2, 'world'))
print(f"finished at {time.strftime('%X')}")
asyncio.run(main())
该结果变为:
started at 14:37:12
hello
world
finished at 14:37:15
这花费了3秒钟,表明协程运行不正确。
我怎样才能使后面的代码正常工作?还是有什么东西导致了这种差异?
P.S.这个例子实际上来自python doc:https://docs.python.org/3.8/library/asyncio-task.html#coroutines
3条答案
按热度按时间bwntbbo31#
await
使代码在等待的协程完成后“停止”并继续,因此当您编写第二个任务是在第一个协同程序完成后创建和运行的,因此总共需要3秒。作为一种解决方案,考虑使用像
gather
或wait
这样的函数。举例来说:输出量:
m3eecexj2#
从docs Await表达式:
暂停对可等待对象执行协程。只能在协程函数中使用。
无论何时执行
await
,例程都会挂起,直到等待的任务完成。在第一个例子中,两个协程都开始,并且第二个协程中的2秒睡眠与第一个相重叠。当您在第一个await
之后开始运行时,第二个计时器中已经过了1秒。在第二个示例中,第二个
await asyncio.create_task(say_after(2, 'world'))
直到第一个完成并且main
继续运行之后才被调度。这是第二个任务的2秒睡眠开始的时候。我结合了这些例子来展示进展。我没有打印原始的输出,而是在
say_after
等待之前打印一条开始消息,在main的await
之后打印一条结束消息。你可以在结果中看到时间差。第二个测试的结果表明,第二个
say_after
直到第一个say_after
完成才被调用。在
main
中,创建了运行asyncio.sleep
的任务,但这些任务直到main
返回even循环时才实际运行。如果我们添加一个time.sleep(3)
,我们可能会期望这两个重叠的sleep已经完成,但实际上say_after
甚至没有运行,直到第一个await
让事件循环继续。产生
在设置任务后将
asyncio.sleep(0)
添加到main
,允许它们运行并执行自己的重叠睡眠,代码可以按照我们的要求工作。wrrgggsh3#
我现在有点明白问题了...
await使进程阻塞在该行。
所以在main函数中,如果你想执行并行任务,最好使用asyncio.wait/gather...
我认为这只是Asyncio的设计风格使以前的代码工作得很好...