再次点击按钮时如何取消运行中的asyncio协程?
修复asyncio任务取消问题的方案
原代码无法正常取消任务的核心问题有三个,下面是针对性的修复方案:
关键问题分析
- 任务列表未持久化:创建任务时用了局部变量,取消分支根本访问不到正在运行的任务
- 阻塞UI事件循环:
await asyncio.wait会让按钮回调一直等待到第一个任务完成,导致后续点击无法响应 - 未处理取消异常:任务被取消时会抛出
CancelledError,未捕获会引发报错
修改后的完整代码
import asyncio import flet as ft class TasksManager: def __init__(self) -> None: self.state = False self.task_funcs = [self.task_1, self.task_2, self.task_3] self.tasks = [] # 用于保存正在运行的任务实例 async def task_1(self): try: for i in range(10): await asyncio.sleep(1) print("Task 1: ", i) except asyncio.CancelledError: print("Task 1 已被取消") async def task_2(self): try: for i in range(10): await asyncio.sleep(1) print("Task 2: ", i) except asyncio.CancelledError: print("Task 2 已被取消") async def task_3(self): try: for i in range(10): await asyncio.sleep(1) print("Task 3: ", i) except asyncio.CancelledError: print("Task 3 已被取消") async def click(self, e: ft.TapEvent): if not self.state: self.state = True # 创建任务并保存到实例属性 self.tasks = [asyncio.create_task(func()) for func in self.task_funcs] print("任务已启动") else: # 取消所有正在运行的任务 for task in self.tasks: if not task.done(): task.cancel() # 等待任务处理取消操作 await task self.state = False self.tasks.clear() print("所有任务已取消") def main(page: ft.Page): manager = TasksManager() button = ft.TextButton("启动/取消任务", on_click=manager.click) page.add(button) page.update() ft.app(main)
核心修改说明
- 新增
self.tasks实例属性,专门保存正在运行的任务对象,确保取消时能访问到 - 移除
await asyncio.wait,让任务在后台异步运行,不阻塞UI回调 - 在每个任务内部添加
try-except捕获CancelledError,处理取消逻辑并避免报错 - 取消任务后调用
await task,确保任务完成取消流程,然后重置state和任务列表
内容的提问来源于stack exchange,提问作者root
相关产品推荐
相关产品推荐

