如何取消执行中的task

"""
1、run_until_complete和run_ forever
2.取消task
"""
import asyncio

loop = asyncio.get_event_loop()
loop.run_until_complete()
loop.run_forever()
# task ->loop
# loop ->task

一、核心知识点

1. run_until_complete vs run_forever

  • loop.run_until_complete(future_or_task)
    • 启动事件循环,直到指定的 Future/Task 完成后停止。
    • 常用于一次性任务(如主协程)。
  • loop.run_forever()
    • 启动事件循环,让其一直运行,直到手动调用 loop.stop()
    • 适合需要长期运行的服务(如服务器)。

2. 取消 Task

  • Task 对象有 cancel() 方法,可以请求取消正在执行的协程。
  • 被取消的协程会在下一个可等待点(await)抛出 asyncio.CancelledError 异常。
  • 你可以在协程内部捕获这个异常,做清理或善后处理。

二、完整代码示例与解释

示例:如何取消一个正在执行的 Task

import asyncio

async def long_task():
    print('Task started')
    try:
        await asyncio.sleep(10)  # 模拟长时间任务
    except asyncio.CancelledError:
        print('Task was cancelled!')
        raise
    print('Task finished')

async def main():
    # 创建任务
    task = asyncio.create_task(long_task())
    await asyncio.sleep(2)  # 让任务先运行2秒
    print('Now cancel the task...')
    task.cancel()           # 请求取消任务
    try:
        await task          # 等待任务被取消并处理异常
    except asyncio.CancelledError:
        print('main: Task cancellation confirmed.')

# 用 run_until_complete 执行 main 协程
asyncio.run(main())

逐行解释

  1. 定义长任务协程

    async def long_task():
        print('Task started')
        try:
            await asyncio.sleep(10)  # 模拟长时间任务
        except asyncio.CancelledError:
            print('Task was cancelled!')
            raise
        print('Task finished')
    
    • long_task 是一个协程,开始时打印“Task started”。
    • await asyncio.sleep(10) 模拟一个耗时10秒的操作。
    • 如果在 sleep 期间被取消,会抛出 asyncio.CancelledError,被 except 捕获,打印“Task was cancelled!”。
  2. 定义主协程

    async def main():
        task = asyncio.create_task(long_task())
        await asyncio.sleep(2)  # 让任务先运行2秒
        print('Now cancel the task...')
        task.cancel()           # 请求取消任务
        try:
            await task          # 等待任务被取消并处理异常
        except asyncio.CancelledError:
            print('main: Task cancellation confirmed.')
    
    • 创建并调度 long_task,返回 Task 对象。
    • 主协程先等待2秒(让 long_task 运行一会儿)。
    • 调用 task.cancel() 请求取消任务。
    • await task 等待任务结束(此时会抛出 CancelledError)。
    • 捕获异常,确认任务已被取消。
  3. 启动事件循环

    asyncio.run(main())
    
    • 启动事件循环,执行 main() 协程,直到其完成。

输出示例

Task started
Now cancel the task...
Task was cancelled!
main: Task cancellation confirmed.

三、Task 与 Loop 的关系

  • Task -> Loop:每个 Task 都属于一个事件循环(loop),由 loop 调度执行。
  • Loop -> Task:事件循环可以管理、调度、取消所有注册的 Task。

四、总结

  • task.cancel() 可以请求取消正在执行的协程任务。
  • 被取消的协程会在下一个 await 处抛出 asyncio.CancelledError,可用于清理和善后。
  • run_until_complete 适合一次性任务,run_forever 适合长期运行服务。
  • Task 和事件循环是相互关联的,Task 由 Loop 调度,Loop 可以取消 Task。
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐