Skip to main content
 首页 » 编程设计

Python 异步 : stop the loop when one coroutine is done

2025年05月04日13dyllove98

我对这个 python asyncio 主题很陌生。我有一个简单的问题: 我有一个包含两个要同时运行的协程的任务。第一个协程(my_coroutine)只会连续打印一些东西,直到达到 second_to_sleep。第二个协程(seq_coroutine)会依次调用另外 4 个协程。我的目标是在 seq_coroutine 完全完成时停止循环。确切地说,我希望 my_coroutine 在 seq_coroutine 完成之前一直存在。有人可以帮我吗?

我的代码是这样的:

import asyncio 
 
async def my_coroutine(task,  seconds_to_sleep = 3): 
    print("{task_name} started\n".format(task_name=task)) 
    for i in range(1, seconds_to_sleep): 
        await asyncio.sleep(1) 
        print("\n{task_name}: second {seconds}\n".format(task_name=task, seconds=i)) 
 
async def coroutine1(): 
    print("coroutine 1 started") 
    await asyncio.sleep(1) 
    print("coroutine 1 finished\n") 
 
 
async def coroutine2(): 
    print("coroutine 2 started") 
    await asyncio.sleep(1) 
    print("coroutine 2 finished\n") 
 
 
async def coroutine3(): 
    print("coroutine 3 started") 
    await asyncio.sleep(1) 
    print("coroutine 3 finished\n") 
 
 
async def coroutine4(): 
    print("coroutine 4 started") 
    await asyncio.sleep(1) 
    print("coroutine 4 finished\n") 
 
 
async def seq_coroutine(): 
    await coroutine1() 
    await coroutine2() 
    await coroutine3() 
    await coroutine4() 
 
def main(): 
    main_loop = asyncio.get_event_loop() 
    task = [asyncio.ensure_future(my_coroutine("task1", 11)), 
            asyncio.ensure_future(seq_coroutine())] 
    try: 
        print('loop is started\n') 
        main_loop.run_until_complete(asyncio.gather(*task)) 
    finally: 
        print('loop is closed') 
        main_loop.close() 
 
 
if __name__ == "__main__": 
    main() 

这是这个程序的输出:

loop is started 
 
task1 started 
 
coroutine 1 started 
 
task1: second 1 
 
coroutine 1 finished 
coroutine 2 started 
 
task1: second 2 
 
coroutine 2 finished 
coroutine 3 started 
 
task1: second 3 
 
coroutine 3 finished 
coroutine 4 started 
 
task1: second 4 
 
coroutine 4 finished 
 
task1: second 5 
task1: second 6 
task1: second 7 
task1: second 8 
task1: second 9 
task1: second 10 
 
loop is closed 

我只想拥有这样的东西:

loop is started 
 
task1 started 
 
coroutine 1 started 
 
task1: second 1 
 
coroutine 1 finished 
coroutine 2 started 
 
task1: second 2 
 
coroutine 2 finished 
coroutine 3 started 
 
task1: second 3 
 
coroutine 3 finished 
coroutine 4 started 
 
task1: second 4 
 
coroutine 4 finished 
 
loop is closed 

请您参考如下方法:

我刚刚找到了适合我的问题的解决方案。 我不会删除我的帖子,我会发布我的解决方案,以便它可以帮助面临同样问题的其他人。 我使用了 asyncio.wait(task, return_when=asyncio.FIRST_COMPLETED) 并且它会在第一个任务完成时返回结果。 这是解决方案:

import asyncio 
from asyncio.tasks import FIRST_COMPLETED 
from concurrent.futures import CancelledError 
 
async def my_coroutine(task,  seconds_to_sleep = 3): 
    print("{task_name} started\n".format(task_name=task)) 
    for i in range(1, seconds_to_sleep): 
        await asyncio.sleep(1) 
        print("\n{task_name}: second {seconds}\n".format(task_name=task, seconds=i)) 
 
async def coroutine1(): 
    print("coroutine 1 started") 
    await asyncio.sleep(1) 
    print("coroutine 1 finished\n") 
 
 
async def coroutine2(): 
    print("coroutine 2 started") 
    await asyncio.sleep(1) 
    print("coroutine 2 finished\n") 
 
 
async def coroutine3(): 
    print("coroutine 3 started") 
    await asyncio.sleep(1) 
    print("coroutine 3 finished\n") 
 
 
async def coroutine4(): 
    print("coroutine 4 started") 
    await asyncio.sleep(1) 
    print("coroutine 4 finished\n") 
 
 
async def seq_coroutine(loop): 
    await coroutine1() 
    await coroutine2() 
    await coroutine3() 
    await coroutine4() 
 
def main(): 
    main_loop = asyncio.get_event_loop() 
    task = [asyncio.ensure_future(my_coroutine("task1", 11)), 
            asyncio.ensure_future(seq_coroutine(main_loop))] 
    try: 
        print('loop is started\n') 
        done, pending = main_loop.run_until_complete(asyncio.wait(task, return_when=asyncio.FIRST_COMPLETED)) 
        print("Completed tasks: {completed}\nPending tasks: {pending}".format(completed = done, pending = pending)) 
 
        #canceling the tasks 
        for task in pending: 
            print("Cancelling {task}: {task_cancel}".format(task=task, task_cancel=task.cancel())) 
 
    except CancelledError as e: 
        print("Error happened while canceling the task: {e}".format(e=e)) 
    finally: 
        print('loop is closed') 
 
 
if __name__ == "__main__": 
    main()