You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Python Asyncio:如何向运行中的事件循环添加新协程?代码问题排查

回答

当然可以实现!你的代码里有两个关键问题导致了当前的阻塞行为:

1. 使用阻塞的time.sleep()而非异步休眠

time.sleep()是同步阻塞函数,一旦调用它,整个事件循环会被彻底卡住,直到休眠结束。这意味着其他协程根本没有机会被调度执行,所以只有第一个协程一直在输出。

在asyncio中,必须使用await asyncio.sleep(waiting_time)来实现异步休眠,这样事件循环可以在休眠期间切换到其他协程运行。

2. 错误地awaitcreate_task()的返回值

loop.create_task()会立即创建一个异步任务并将其加入事件循环,但你在循环里使用await loop.create_task(...),这会强制等待第一个任务完成才会创建下一个任务。而你的secondCoro是无限循环,所以第一个任务永远不会结束,后面的9个协程根本没机会被创建。

修复后的代码

下面是调整后的代码,解决了以上两个问题:

import asyncio
import random

async def secondCoro(myId):
    while 1:
        waiting_time = random.randint(1,5)
        print(f"i am {myId} ")
        await asyncio.sleep(waiting_time)  # 使用异步休眠

async def main():
    tasks = []
    for i in range(10):
        task = asyncio.create_task(secondCoro(i))  # 创建任务但不立即等待
        tasks.append(task)
        await asyncio.sleep(0.1)  # 这里用异步sleep避免阻塞
    
    # 等待所有任务完成(因为是无限循环,这里实际会一直运行)
    await asyncio.gather(*tasks)

# Python 3.7+推荐使用asyncio.run()替代get_event_loop()
asyncio.run(main())

运行这段代码,你会看到10个协程交替输出,完全符合你的预期。

其他运行多协程的常用方法

1. 使用asyncio.gather()批量等待任务

这是最常用的方式,适合批量创建任务并等待所有任务完成:

async def main():
    tasks = [asyncio.create_task(secondCoro(i)) for i in range(10)]
    await asyncio.gather(*tasks)

2. 使用asyncio.wait()控制任务等待方式

asyncio.wait()可以选择等待所有任务完成(return_when=asyncio.ALL_COMPLETED)或者第一个任务完成(asyncio.FIRST_COMPLETED):

async def main():
    tasks = [asyncio.create_task(secondCoro(i)) for i in range(10)]
    done, pending = await asyncio.wait(tasks, return_when=asyncio.ALL_COMPLETED)

3. Python 3.11+:使用asyncio.TaskGroup()(推荐)

任务组是Python 3.11引入的新特性,提供了更简洁、安全的方式管理异步任务,自动处理异常:

async def main():
    async with asyncio.TaskGroup() as tg:
        for i in range(10):
            tg.create_task(secondCoro(i))
            await asyncio.sleep(0.1)
    # 退出上下文管理器时,会自动等待所有任务完成

任务组会自动处理任务中的异常,避免因为单个任务崩溃导致整个程序终止,是现代asyncio开发的首选方式。

内容的提问来源于stack exchange,提问作者wisnshaftler

火山引擎 最新活动