来自文档Await expression:
在等待对象上暂停协程的执行。只能是
在协程函数中使用。
每当您await 时,例程都会暂停,直到等待的任务完成。在第一个示例中,两个协程都启动,并且第二个中的 2 秒睡眠与第一个重叠。当您在第一个 await 之后开始运行时,第二个计时器已经过了 1 秒。
在第二个示例中,第二个await asyncio.create_task(say_after(2, 'world')) 直到第一个完成并且main 继续运行之后才被调度。这就是第二个任务的 2 秒睡眠开始的时间。
我已结合示例来展示进度。而不是原来的打印,我在say_after 等待之前打印一条开始消息,并在main 的await 之后打印一条完成消息。您可以在结果中看到时差。
import asyncio, time
async def say_after(delay, what):
print(f"start {what} at {time.strftime('%X')}")
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'))
await task1
print(f"Finished hello at {time.strftime('%X')}")
await task2
print(f"Finished world at {time.strftime('%X')}")
async def main2():
await asyncio.create_task(say_after(1, 'hello'))
print(f"Finished hello at {time.strftime('%X')}")
await asyncio.create_task(say_after(2, 'world'))
print(f"Finished world at {time.strftime('%X')}")
print("========== Test 1 ============")
asyncio.run(main())
print("========== Test 2 ============")
asyncio.run(main2())
第二个测试的结果表明,第二个 say_after 在第一个完成之前不会被调用。
========== Test 1 ============
start hello at 00:51:42
start world at 00:51:42
hello
Finished hello at 00:51:43
world
Finished world at 00:51:44
========== Test 2 ============
start hello at 00:51:44
hello
Finished hello at 00:51:45
start world at 00:51:45
world
Finished world at 00:51:47
在main 中,创建任务以运行asyncio.sleep,但这些任务直到main 返回偶数循环后才真正运行。如果我们添加一个time.sleep(3),我们可能会认为这两个重叠的异步睡眠已经完成,但实际上say_after 甚至直到第一个让事件循环继续的await 才运行。
import asyncio, time
async def say_after(delay, what):
print(f"starting {what} at {time.time()-start}")
await asyncio.sleep(delay)
print(what)
async def main():
global start
print('time asyncio.sleep with intermedite time.sleep')
start = time.time()
task1 = asyncio.create_task(say_after(1, 'hello'))
task2 = asyncio.create_task(say_after(2, 'world'))
# similate working for 3 seconds with non asyncio sleep
time.sleep(3)
print(f'expect 3 got {time.time()-start}')
await task1 # <== where the 2 `say_after` tasks start
print(f'expect 3 got {time.time()-start}')
await task2
print(f'expect 3 got {time.time()-start}')
asyncio.run(main())
生产
time asyncio.sleep with intermedite time.sleep
expect 3 got 3.0034446716308594
starting hello at 3.003699541091919
starting world at 3.0038907527923584
hello
expect 3 got 4.005880355834961
world
expect 3 got 5.00671124458313
在设置任务后将asyncio.sleep(0) 添加到main 允许它们运行并执行自己的重叠睡眠,并且代码可以按照我们的意愿运行。
import asyncio, time
async def say_after(delay, what):
print(f"starting {what} at {time.time()-start}")
await asyncio.sleep(delay)
print(what)
async def main():
global start
print('time asyncio.sleep with event loop poll and intermedite time.sleep')
start = time.time()
task1 = asyncio.create_task(say_after(1, 'hello'))
task2 = asyncio.create_task(say_after(2, 'world'))
# let the `say_after` tasks (and anything else pending) run
await asyncio.sleep(0)
# similate working for 3 seconds with non asyncio sleep
time.sleep(3)
print(f'expect 3 got {time.time()-start}')
await task1 # <== where the 2 `say_after` tasks start
print(f'expect 3 got {time.time()-start}')
await task2
print(f'expect 3 got {time.time()-start}')
asyncio.run(main())