当前位置:首页 > 文章列表 > 文章 > python教程 > Python sched 怎样取消尚未触发的定时事件

Python sched 怎样取消尚未触发的定时事件

来源:17golang原创 2026-10-29 18:20:53 0浏览 收藏

Python sched 取消尚未触发的定时事件,关键是保存 scheduler.enter() 或 enterabs() 返回的事件对象,再把这个对象传给同一个调度器的 cancel()。不要根据执行时间、优先级或回调函数去猜目标;事件已经不在队列时,cancel() 会抛出 ValueError。

官方地址:https://docs.python.org/3/library/sched.html

下面的示例只讨论“事件还没触发时如何撤销”这一条路径。文中的图片是静态结构说明图,用来解释事件句柄与队列关系,不是终端、编辑器或程序运行截图。

先保存 enter 返回的事件句柄

enter(delay, priority, action, ...) 和 enterabs(time, priority, action, ...) 都会返回一个事件对象。这个返回值就是后续取消时需要传入的对象,业务代码应把它放在任务记录、字典或对象属性中。

例如,给每个业务任务绑定一个事件句柄,取消时只按业务任务编号取句柄,不用遍历 scheduler.queue 查找相同的函数或时间。这样即使多个事件使用同一个回调,仍能精确取消其中一个。

scheduler enter 返回事件句柄并由 cancel 移除队列事件的静态结构说明图
图1:事件句柄、调度器队列与 cancel 接口的静态关系说明图;这是说明图,不是运行截图。

把事件对象传给同一个 scheduler.cancel

取消动作很短:先调用 enter() 保存返回值,业务条件不再成立时调用 cancel(event)。取消成功后,该事件从调度队列移除,原先的 action 不会再被这个调度器触发。

import sched
import time


def send_reminder(task_name):
    # 回调只表示事件触发后的业务动作。
    print(f"发送提醒:{task_name}")


scheduler = sched.scheduler(time.monotonic, time.sleep)

# 保存 enter 返回的事件句柄,而不是只保存 delay 或回调函数。
event = scheduler.enter(
    30,
    1,
    send_reminder,
    argument=("提交日报",),
)

# 业务状态改变后,在事件触发前撤销这一个事件。
scheduler.cancel(event)

# 取消后再运行调度器,队列中没有该提醒,因此不会调用回调。
scheduler.run()

这里的 event 只属于创建它的 scheduler。不能把另一个调度器创建的事件句柄交给当前调度器,也不能在取消后继续把同一个句柄当成“仍在队列”的标志。

cancel event 的队列存在性和 ValueError 边界静态结构说明图
图2:取消接口与队列存在性边界的静态关系说明图,突出成功移除和 ValueError 两种结果;这是说明图,不是运行截图。

为什么重复取消会得到 ValueError

官方文档规定,如果传入的事件当前不在队列中,cancel() 会抛出 ValueError。常见原因有三个:同一个句柄已经取消过、事件已经到期并被 run() 执行,或者句柄来自另一个调度器。

如果取消动作可能被多个业务分支触发,可以把“是否仍待取消”作为业务状态,并在边界处捕获异常:

def cancel_if_pending(scheduler, event):
    # 取消只能作用于当前队列仍持有的事件。
    try:
        scheduler.cancel(event)
    except ValueError:
        # 事件可能已取消或已由 run() 取出;这里按幂等撤销处理。
        return False
    return True

这个函数把“取消成功”和“已经没有可取消事件”区分开。若业务必须知道事件是否已经触发,则不要只吞掉异常,应在任务记录中维护 pending、cancelled 和 fired 等状态,并由调度线程或回调更新它们。

不要用 scheduler.queue 替代 cancel

scheduler.queue 是只读属性,展示即将运行的事件列表,其中包含时间、优先级、回调、位置参数和关键字参数。它适合观察队列,不适合作为取消协议:列表中的字段可能相同,业务也容易在读取和取消之间遇到竞态。

更稳妥的做法是建立“业务任务编号 → event 句柄”的映射,并让创建、撤销、完成都经过同一个任务对象:

pending = {}


def schedule_task(scheduler, task_id, delay):
    # 用业务编号保存唯一事件句柄,后续按编号取消。
    event = scheduler.enter(delay, 1, send_reminder, argument=(task_id,))
    pending[task_id] = event
    return event


def cancel_task(scheduler, task_id):
    # 先移除业务映射,避免后续分支重复拿到旧句柄。
    event = pending.pop(task_id, None)
    if event is None:
        return False
    try:
        scheduler.cancel(event)
    except ValueError:
        # 事件已不在队列,交给上层根据任务状态决定是否告警。
        return False
    return True

示例的重点不是让字典成为新的调度器,而是让业务拥有稳定的撤销入口。实际项目中如果调度器由独立线程驱动,应通过线程安全的命令队列或锁来协调 pending 映射和 cancel() 调用。

按事件状态选择处理方式

事件状态处理方式原因
已创建,仍在队列中保存的句柄调用 cancel(event)这是官方取消接口支持的状态
已经取消不要再次取消,或捕获 ValueError事件已不在队列
已被 run() 执行取消回调产生的业务后果事件已经越过可取消边界
句柄属于另一个 scheduler回到创建它的调度器处理取消对象与调度器必须匹配

可以把结论压缩成一句话:sched 的取消是“按事件对象从所属队列移除”,不是“按条件删除未来时间点”。只要把 enter() 的返回值当作任务生命周期的一部分,取消逻辑就会清晰很多。

相关问题

能不能按回调函数取消 sched 事件?

不建议。官方接口接收的是 enter() 返回的事件对象;多个事件可以共用同一个回调,按回调查找会失去精确性。

取消事件后需要清空整个 scheduler 吗?

不需要。cancel(event) 只移除指定事件,其他仍有效的事件会保留。

事件触发后还能用 cancel 撤销吗?

不能把它当作尚未触发的事件处理。事件一旦已从队列取出或执行,再调用取消可能得到 ValueError;此时要处理已经发生的业务动作。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Python sched.scheduler 怎样让 run 不阻塞等待下个事件Python sched.scheduler 怎样让 run 不阻塞等待下个事件
上一篇
Python sched.scheduler 怎样让 run 不阻塞等待下个事件
Python mailbox.Maildir 怎样区分新邮件与已读邮件
下一篇
Python mailbox.Maildir 怎样区分新邮件与已读邮件
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    777次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    772次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    858次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    823次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    652次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码