阅读文档并观看了许多视频后,我正在测试asyncio
作为threading
的替代方案。
文档在这里: https://docs.python.org/3/library/asyncio.html
我构造了以下代码,期望它会生成以下内容。
before the sleep
hello
world
但实际上产生这个(world
在hello
之前):
before the sleep
world
hello
这是代码:
import asyncio
import time
def main():
''' main entry point for the program '''
# create the event loop and add to the loop
# or run directly.
asyncio.run(main_async())
return
async def main_async():
''' the main async function '''
await foo()
await bar()
return
async def foo():
print('before the sleep')
await asyncio.sleep(2)
# time.sleep(0)
print('world')
return
async def bar():
print('hello')
await asyncio.sleep(0)
return
if __name__=='__main__':
''' This is executed when run from the command line '''
main()
main()
函数调用异步main_async()
函数,该函数又调用foo
和bar
异步函数,这两个函数都运行await asyncio.sleep(x)
命令。
所以我的问题是:为什么hello
world
以错误的(意外)顺序出现,因为我预计world
会在hello
后大约 2 秒打印?
您立即await
edfoo()
,因此在foo()
运行完成之前从未安排bar()
;在await
完成之前,main_async
的执行永远不会在await
后执行操作。如果要安排它们并让它们交错,请替换:
await foo()
await bar()
像这样:
await asyncio.gather(foo(), bar())
这会将两个 awaitable 转换为任务,在正在运行的 asyncio 事件循环中调度这两个任务,然后等待两个任务运行完成。同时计划两者时,当一个块在await
上时(并且只有基于await
的块,因为只有await
将控制权交还给事件循环),另一个将被允许运行(并且控制只能在当前正在运行的任务await
或完成时返回到另一个任务)。
基本上,您必须记住asyncio
是协作式多任务处理。如果您只执行一项任务,并且该任务执行await
,则没有其他要计划的内容,因此在该await
完成之前不会运行任何其他任务。如果您通过除await
以外的任何方式阻止,您仍然保持事件循环,即使它已准备就绪,其他任何东西都不会有机会运行。因此,要从asyncio
中获得任何好处,您需要小心:
- 确保在原始任务阻塞
await
时及时启动其他任务以占用事件循环。 - 确保只通过
await
阻塞,这样就不会不必要地独占事件循环。