来自同步(标准)函数的 asyncio 运行
asyncio running from a synchronous (standard) function
阅读了文档并观看了一些视频后,我正在测试 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
立即编辑了 foo()
,因此 bar()
从未安排到 foo()
已 运行 完成;在 await
完成之前,main_async
的执行永远不会在 和 await
之后执行 事情。如果你想同时安排它们并让它们交错,替换:
await foo()
await bar()
类似的东西:
await asyncio.gather(foo(), bar())
这会将两个可等待对象转换为任务,在 运行ning 异步事件循环中安排它们,然后等待两个任务 运行 完成。两者同时安排,当一个块在 await
(和 仅 await
块上时,因为只有 await
将控制权交还给事件循环),另一个将被允许 运行(当现在 运行ning 任务 await
或完成时,控制只能 return 到另一个任务)。 =30=]
基本上,您必须记住 asyncio
是 合作 多任务处理。如果您只执行一项任务,并且该任务执行 await
,则没有其他可安排的任务,因此在 await
完成之前没有其他 运行s。如果您通过 await
以外的任何方式进行阻止,您仍然会保持事件循环,即使它已准备就绪,也没有其他任何机会进入 运行。因此,要从 asyncio
中获得任何好处,您需要注意:
- 确保在原始任务阻塞
await
时及时启动其他任务以占用事件循环。
- 确保你只通过
await
阻塞,这样你就不会不必要地独占事件循环。
阅读了文档并观看了一些视频后,我正在测试 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
立即编辑了 foo()
,因此 bar()
从未安排到 foo()
已 运行 完成;在 await
完成之前,main_async
的执行永远不会在 和 await
之后执行 事情。如果你想同时安排它们并让它们交错,替换:
await foo()
await bar()
类似的东西:
await asyncio.gather(foo(), bar())
这会将两个可等待对象转换为任务,在 运行ning 异步事件循环中安排它们,然后等待两个任务 运行 完成。两者同时安排,当一个块在 await
(和 仅 await
块上时,因为只有 await
将控制权交还给事件循环),另一个将被允许 运行(当现在 运行ning 任务 await
或完成时,控制只能 return 到另一个任务)。 =30=]
基本上,您必须记住 asyncio
是 合作 多任务处理。如果您只执行一项任务,并且该任务执行 await
,则没有其他可安排的任务,因此在 await
完成之前没有其他 运行s。如果您通过 await
以外的任何方式进行阻止,您仍然会保持事件循环,即使它已准备就绪,也没有其他任何机会进入 运行。因此,要从 asyncio
中获得任何好处,您需要注意:
- 确保在原始任务阻塞
await
时及时启动其他任务以占用事件循环。 - 确保你只通过
await
阻塞,这样你就不会不必要地独占事件循环。