当前位置:首页 > 文章列表 > Golang > Go教程 > Go Ticker 怎样停止长生命周期定时器

Go Ticker 怎样停止长生命周期定时器

来源:17golang原创 2026-10-22 20:25:31 0浏览 收藏

停止 Go 的长生命周期 Ticker,通常需要三个独立动作:用 ticker.Stop() 停止计时,用 Context 通知工作循环退出,再用结果通道或其他同步方式确认任务已经结束。只调用 Stop,不能让 for range ticker.C 自动结束,因为它不会关闭这个通道。

下面给出一个串行周期任务的完整约定:谁创建 Ticker,谁负责停止;调用方只发取消请求并等待结果。它适合配置轮询、周期刷新等允许按节拍触发的工作,不是保证每个周期都执行一次的可靠任务队列。

Go 官方地址:https://go.dev/
time 包文档:https://pkg.go.dev/time

最小写法:Stop和退出信号要分开

把下面函数放到程序中,所需导入见后面的 main.go 入口。参数 every 控制周期,job 接收同一个 Context;示例约定任务首次报错就终止,而不是无限重试。

// RunPeriodic 串行执行周期任务;调用方保证 ctx 非 nil。
func RunPeriodic(ctx context.Context, every time.Duration,
    job func(context.Context) error) error {
    if every 

创建 Ticker 前先拒绝无效参数,函数退出时用 defer 统一停止它。循环同时等待计时通道和取消信号,取消分支执行 return,而不是只跳出 select。官方 Ticker.Stop 没有返回值,不能套用 Timer.Stop 的布尔返回值写法。Ticker.Stop 文档

把创建、运行和回收交给同一个所有者

在这个约定中,RunPeriodic 是工作循环的所有者。Ticker 属于这个循环,ticker.C 只是节拍接收入口,ticker.Stop 是该资源的停止操作。Context 负责传入取消信号,job 负责真正的业务动作;这几个职责不能互相替代。

运行阶段只创建一个 Ticker,不在每轮循环里不断 NewTicker。正常取消、业务报错都通过函数返回,使 defer Stop 覆盖资源释放路径。对于长时间运行的服务,defer 应位于这个工作函数里,而不是堆在永远不返回的外层管理循环中。

RunPeriodic关联Ticker及其通道和Stop操作,Context与job属于任务协作边界
图1:周期任务职责结构图。两个分组区分计时资源与任务协作,连线表示所属、使用和参数关系,不是执行流程或运行截图。

调用方取消以后还要等待done

把上节函数与下面代码合并为一个 main.go。它等到首次任务通知后取消,再收到 done 结果;这里没有依赖固定 Sleep 猜测 worker 是否启动。示例打印的是任务入口和退出确认,实际工作留给 job。

package main

import (
    "context"
    "errors"
    "fmt"
    "time"
)

// 把上节 RunPeriodic 函数放在同一个 main.go 文件中。
func main() {
    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()
    done := make(chan error, 1) // 缓冲结果,让 worker 返回不依赖接收时机。
    started := make(chan struct{})
    go func() {
        first := true // 仅由此 goroutine 访问,无需跨线程共享。
        done 

started 是首次任务进入的通知;done 是 worker 返回的结果。RunPeriodic 返回前已经执行 defer Stop,因此收到 done 的值可以确认这个循环已退出。调用方收到信号不等于业务事务自动回滚;如果 job 启动了自己的子 goroutine,还要由 job 负责等待和回收它们。

Context 的 CancelFunc 只表达取消意图,不提供等待保证;这里额外设置 done 是应用的同步设计。CancelFunc 文档

main持有cancel并接收done,worker调用RunPeriodic并发送错误结果
图2:取消与完成确认的接口关系图。“调用方”和“工作方”分别持有不同职责,线上的标签说明调用、结果传递与接收,不暗示时间轴。

读者可在新的练习目录创建模块、保存代码后运行:

# 创建模块并保存包含两个代码片段的 main.go 后运行。
go mod init example.com/ticker-lifecycle
go run .

按代码约定应先出现“开始一次周期任务”,最终出现“周期任务已退出”。这是供复现的预期行为,不是本机执行记录;不要用固定 tick 数量或精确耗时作为这个示例的正确性条件。

慢任务和取消同时发生时怎样处理

select 不按书写顺序优先取消。当 ticker.C 和 ctx.Done 同时可接收时,规范不保证先选取消。因此 tick 分支再查 ctx.Err,能够拒绝已经可观察到的取消;但检查与 job 调用之间仍有竞态窗口,不构成“取消瞬间之后绝不进入任何任务”的强保证。需要更严格的业务屏障,应另设计串行所有权或提交协议。select 语句规则

已经进入 job,循环不会替它抢占退出。job 执行阻塞 I/O 时,应把 jobCtx 传给支持 Context 的接口,并为不支持取消的依赖设置合适的超时。job 如果永久阻塞,调用方即便 cancel 也可能一直等不到 done;增加等待超时只是让调用方停止等待,并不代表 worker 被终止。

本例只串行调用 job。不要为了“赶上周期”把每个 tick 改成无上限的 go job(ctx),否则还需要并发限制、任务等待和错误汇总。慢接收方可能使 Ticker 调整或丢弃节拍,它不保存一份可靠的待办列表。NewTicker 对慢接收方的说明

Go新旧计时器语义要分清

Go 1.23 对基于通道的计时器实现做过两类重要调整:不再被引用的未停止计时器可以被垃圾回收;新语义下计时通道采用同步行为,减少 Stop、Reset 后旧值带来的问题。是否使用该实现还与主模块 go.mod 的 go 指令和 GODEBUG=asynctimerchan 设置有关,不能只看到工具链版本就把旧语义排除。具体兼容条件应按 Go 官方说明判断。Go 计时通道变化说明

这些变化没有把 Stop 变成 goroutine 取消接口。仍被 worker 持有、仍参与循环的 Ticker,也不能靠“新版本能回收”表达业务停止。本文显式使用 defer Stop,不依赖 GC 时机;也不需要读取 len(ticker.C) 判断是否停止,或用阻塞接收去“清空”一个停止后的通道。

若项目在兼容旧计时通道语义,Stop 前可能存在待接收的旧节拍;本文的退出依据是 Context 和函数返回,而不是等通道耗尽。这样能把业务关闭协议与计时器内部缓存行为分开。

把常见写法放到一张速查表里

动作或写法作用不能代替什么
ticker.Stop()停止计时不关闭 C,不终止 job,不等待循环
cancel()发出协作取消请求不等待任务完成
接收 done 结果按本例协议确认循环返回不自动收回 job 私自启动的子任务
ticker.Reset(d)更新周期并重新安排节拍不是业务退出操作
for range ticker.C接收节拍无法靠 Stop 获得通道关闭通知

可以手动 close(ticker.C) 吗?不可以把计时通道当作自己的完成通道;它暴露的是只读通道。业务通知使用自建通道,并约定唯一的关闭者。

停止以后还想恢复怎么办?单纯调整同一工作循环的周期可设计 Reset 控制入口,并让所有者统一处理。若 RunPeriodic 已返回,应重新创建一轮生命周期,不要复用已经结束的 done 结果来冒充新任务状态。

取消时业务错误算哪一种结果?本例通过 %w 包装原始错误,调用方能用 errors.Is 判断 context.Canceled;其他业务错误仍单独处理。实际任务若忽略 Context 并成功返回,循环会在下一次检查中看到取消,而不是强行修改业务已经完成的事实。

推荐约定可以压缩为一句话:创建者停止计时器,工作循环响应取消,调用方等待完成确认。Stop、cancel 和 done 各管一件事,长生命周期任务的停止过程才有清楚的归属。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
手机壁纸 黑金流线 怎样处理手机壁纸 黑金流线 怎样处理
上一篇
手机壁纸 黑金流线 怎样处理
手机壁纸 暮蓝玻璃波纹怎样安排主体层次
下一篇
手机壁纸 暮蓝玻璃波纹怎样安排主体层次
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之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模型性能。
    592次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    627次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    661次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    631次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    445次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码