`asyncio` 循环中的饥饿
Starvation in `asyncio` loop
我有一个系统,其中两个“进程”A
和 B
运行 在同一个 asyncio
事件循环中。
我注意到启动进程的顺序很重要 - 即如果我先启动进程 B
然后一直进程 B
运行s,而似乎 A
资源“匮乏”,反之亦然。
根据我的经验,这可能发生的唯一原因是 mutex
没有被 B
发布,但在下面的玩具示例中,它发生时没有任何 mutex
] 正在使用:
import asyncio
async def A():
while True:
print('A')
await asyncio.sleep(2)
async def B():
while True:
print('B')
await asyncio.sleep(8)
async def main():
await B()
await A()
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
是在python
进程不自动执行上下文切换?如果不是 - 我怎样才能让两个进程都参与其中,每个进程都在另一个进程空闲(即休眠)时参与?
TLDR:协程仅启用并发,它们不会自动触发并发。显式启动单独的任务,例如通过 create_task
或 gather
,并发 运行 协程。
async def main():
await asyncio.gather(B(), A())
asyncio
中的并发是通过任务处理的——与线程非常相似——它仅 由 组成 coroutines/awaitables——就像线程 由 functions/callables 组成。一般来说,一个coroutine/awaitable本身并不等同于一个单独的任务。
使用await X()
表示“开始X
并等待它完成”。当按顺序使用多个这样的结构时:
async def main():
await B()
await A()
这意味着首先启动 B
,只有在 B
完成后才启动 A
:而 async def
和 await
允许并发 其他任务、B
和A
在单个任务中相对于彼此顺序运行。
添加并发的最简单方法是显式创建任务:
async def main():
# execute B in a new task
b_task = asyncio.create_task(B())
# execute A in the current task
await A()
await b_task
请注意 B
如何卸载到新任务,同时仍然可以执行最终 await A()
以重新使用当前任务。
大多数异步框架都附带了用于常见并发场景的高级助手。在这种情况下,asyncio.gather
适合同时启动多个任务:
async def main():
# execute B and A in new tasks
await asyncio.gather(B(), A())
我有一个系统,其中两个“进程”A
和 B
运行 在同一个 asyncio
事件循环中。
我注意到启动进程的顺序很重要 - 即如果我先启动进程 B
然后一直进程 B
运行s,而似乎 A
资源“匮乏”,反之亦然。
根据我的经验,这可能发生的唯一原因是 mutex
没有被 B
发布,但在下面的玩具示例中,它发生时没有任何 mutex
] 正在使用:
import asyncio
async def A():
while True:
print('A')
await asyncio.sleep(2)
async def B():
while True:
print('B')
await asyncio.sleep(8)
async def main():
await B()
await A()
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
是在python
进程不自动执行上下文切换?如果不是 - 我怎样才能让两个进程都参与其中,每个进程都在另一个进程空闲(即休眠)时参与?
TLDR:协程仅启用并发,它们不会自动触发并发。显式启动单独的任务,例如通过 create_task
或 gather
,并发 运行 协程。
async def main():
await asyncio.gather(B(), A())
asyncio
中的并发是通过任务处理的——与线程非常相似——它仅 由 组成 coroutines/awaitables——就像线程 由 functions/callables 组成。一般来说,一个coroutine/awaitable本身并不等同于一个单独的任务。
使用await X()
表示“开始X
并等待它完成”。当按顺序使用多个这样的结构时:
async def main():
await B()
await A()
这意味着首先启动 B
,只有在 B
完成后才启动 A
:而 async def
和 await
允许并发 其他任务、B
和A
在单个任务中相对于彼此顺序运行。
添加并发的最简单方法是显式创建任务:
async def main():
# execute B in a new task
b_task = asyncio.create_task(B())
# execute A in the current task
await A()
await b_task
请注意 B
如何卸载到新任务,同时仍然可以执行最终 await A()
以重新使用当前任务。
大多数异步框架都附带了用于常见并发场景的高级助手。在这种情况下,asyncio.gather
适合同时启动多个任务:
async def main():
# execute B and A in new tasks
await asyncio.gather(B(), A())