从同步(标准)函数运行的异步



阅读文档并观看了许多视频后,我正在测试asyncio作为threading的替代方案。

文档在这里: https://docs.python.org/3/library/asyncio.html

我构造了以下代码,期望它会生成以下内容。

before the sleep
hello
world

但实际上产生这个(worldhello之前):

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()函数,该函数又调用foobar异步函数,这两个函数都运行await asyncio.sleep(x)命令。

所以我的问题是:为什么helloworld以错误的(意外)顺序出现,因为我预计world会在hello后大约 2 秒打印?

您立即awaitedfoo(),因此在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中获得任何好处,您需要小心:

  1. 确保在原始任务阻塞await时及时启动其他任务以占用事件循环。
  2. 确保只通过await阻塞,这样就不会不必要地独占事件循环。

最新更新