资讯动态

仓颉 std.sync 定时器 Timer 完全指南:一次性与重复性任务调度的 API 解析与实战

发布时间:2026/10/15 3:34:55 来源:尧图企业网站定制
人工智能AI 技能文档开发工具【免费下载链接】DocAgent项目地址https://gitcode.com/Cangjie-SIG/DocAgent点击查看免费下载本文以仓颉标准库std.sync包中的Timer类API 文档为核心系统讲解其在指定时间点或时间间隔后执行任务场景下的完整用法一次性任务与重复性任务的四种创建方式、after返回值驱动的动态调度机制、CatchupStyle三种追平策略的选型以及cancel取消与生命周期管理。读完本文你将掌握在仓颉并发程序中正确使用Timer创建、控制和回收定时任务的全套能力并理解其不保证准时、保证不晚于当前时间等底层语义。Timer 是什么并发包中的定时器抽象Timer是仓颉标准库std.sync包提供的定时器功能用于在指定时间点或指定时间间隔后执行指定任务Task一次或多次。从类声明见 sync_package_classes.md看public class Timer : EquatableTimer Hashable它实现了EquatableTimer与Hashable两个接口因此Timer实例支持基于同一实例的相等比较与哈希可用作集合元素。在使用之前需要先理解Timer的几个关键语义约束它们直接影响你的程序行为隐式 spawn每个Timer在创建时会隐式包含一次spawn操作即每个Timer会创建一个仓颉线程仓颉线程是 M:N 用户态轻量线程详见 sync_package_overview.md用于执行该 Timer 关联的 Task。单 Task 绑定每个Timer只能在初始化时绑定一个 Task初始化完成后无法重置关联的 Task。生命周期与 GC只有关联 Task 执行完毕或通过cancel接口主动取消 TimerTimer 的生命周期才会结束之后才能被 GC 回收。换句话说在 Task 执行完毕或被主动取消之前Timer 实例不会被 GC 回收从而确保关联 Task 能被正常执行。时间保证系统繁忙时 Task 的触发时间可能被影响。Timer 不保证 Task 的触发时间一定准时但保证 Task 的触发时间小于等于当前时间。异常语义Timer 不会主动捕获关联 Task 抛出的异常只要 Task 有未被捕获的异常该 Timer 就会失效。按使用方式Timer 通常分为一次性任务定时器Task 只执行一次和重复性任务定时器Task 按指定周期执行直到主动cancel或达到创建时指定的结束条件。创建一次性定时任务Timer.onceonce用于设置并启动一次性定时任务返回控制这个任务的Timer对象实例public static func once(delay: Duration, task: ()-Unit): Timer参数说明delay从现在开始到 Task 被执行的时间间隔取值范围[Duration.Min, Duration.Max]小于或等于Duration.Zero时 Task 将立即被执行。task待定时执行的任务无参、无返回值的 lambda。官方 API 文档中的示例sync_package_classes.mdimport std.time.MonoTime main() { let start MonoTime.now() Timer.once(Duration.second, { println(Tick at: ${MonoTime.now() - start}) }) sleep(Duration.second * 2) 0 }运行结果不同机器会有微小偏差Tick at: 1s2ms74us551ns可以看到Task 在约 1 秒后触发且仅触发一次。Duration是仓颉标准库std.core中表示时间间隔的结构体提供nanosecond、millisecond、second、minute、hour、day等静态常量以及Zero、Min、Max三个边界常量详见 Duration_struct.md上述所有时长参数均以它为单位。创建重复性定时任务repeat / repeatDuring / repeatTimes重复性任务定时器有三种创建方式分别对应无条件周期执行、限时执行、限次执行三种结束条件。repeat按固定周期重复执行public static func repeat(delay: Duration, interval: Duration, task: ()-Unit, style!: CatchupStyle Burst): Timerdelay从现在开始到 Task 首次被执行的时间间隔取值范围[Duration.Min, Duration.Max]小于或等于Duration.Zero时立即执行。interval两次 Task 之间的时间间隔取值范围(Duration.Zero, Duration.Max]。task待定时执行的任务。style!追平策略默认Burst详见下文 CatchupStyle 追平策略。异常当interval小于等于Duration.Zero时抛出IllegalArgumentException异常类文档。官方示例sync_package_classes.mdimport std.sync.{Timer} import std.time.{MonoTime} main() { let start MonoTime.now() let timer Timer.repeat(Duration.second, Duration.second, { println(Tick at: ${MonoTime.now() - start}) }) sleep(Duration.second * 5) timer.cancel() 0 }运行结果Tick at: 1s2ms72us188ns Tick at: 2s4ms185us160ns Tick at: 3s6ms275us464ns Tick at: 4s8ms18us399ns Tick at: 5s9ms621us394ns注意repeat创建的任务没有自动结束条件必须由调用方持有返回的Timer实例在合适时机调用cancel()停止调度。repeatDuring限定重复周期的最大持续时间public static func repeatDuring(period: Duration, delay: Duration, interval: Duration, task: () - Unit, style!: CatchupStyle Burst): Timerperiod重复周期的最大持续时间从delay之后开始计时取值范围(Duration.Zero, Duration.Max]。delay、interval、task、style!含义与repeat相同。异常当period小于等于Duration.Zero或interval小于等于Duration.Zero时抛出IllegalArgumentException。官方示例sync_package_classes.mdimport std.sync.{Timer} import std.time.{MonoTime} main() { let start MonoTime.now() Timer.repeatDuring(Duration.second * 5, Duration.second, Duration.second, { println(Tick at: ${MonoTime.now() - start}) }) sleep(Duration.second * 7) 0 }运行结果Tick at: 1s2ms372us626ns Tick at: 2s4ms714us879ns Tick at: 3s6ms769us623ns Tick at: 4s8ms780us235ns Tick at: 5s660us104ns Tick at: 6s3ms257us508ns从输出可见任务从第 1 秒开始每 1 秒触发一次到达第 5 秒的周期上限后定时器在下一周期节点约第 6 秒还会再执行一次以收尾——周期结束后不会立即中断正在排程的最后一次任务这与最大持续时间的语义一致。周期结束后 Timer 自动失效无需手动取消。repeatTimes限定最大执行次数public static func repeatTimes(count: Int64, delay: Duration, interval: Duration, task: () - Unit, style!: CatchupStyle Burst): TimercountTask 最大执行次数取值范围(0, Int64.Max]。delay、interval、task、style!含义同repeat。异常当count 0或interval小于等于Duration.Zero时抛出IllegalArgumentException。官方示例sync_package_classes.mdimport std.sync.{Timer} import std.time.{MonoTime} main() { let start MonoTime.now() Timer.repeatTimes(3, Duration.second, Duration.second, { println(Tick at: ${MonoTime.now() - start}) }) sleep(Duration.second * 4) 0 }运行结果Tick at: 1s2ms855us251ns Tick at: 2s5ms390us18ns Tick at: 3s7ms935us552nsTask 恰好执行 3 次后定时器自动失效无需手动取消。返回值驱动的动态调度Timer.afterafter是四种创建方式中唯一由 Task 返回值决定是否继续、间隔多久的动态调度接口public static func after(delay: Duration, task: () - OptionDuration): Timer调度规则如下sync_package_classes.md如果定时器第一次触发的时间点小于当前时间关联 Task 会立刻被调度执行如果关联 Task 的返回值为Option.None该 Timer 将会失效并停止调度关联 Task如果关联 Task 的返回值为Option.Some(v)且v大于Duration.Zero下次运行前的最小时间间隔将被设置为v否则返回Some(v)且v Duration.Zero关联 Task 会立刻再次被调度执行。其中OptionT是仓颉标准库中可能有值也可能无值的封装类型Some携带一个值、None不带值详见 Option_enum.md。after非常适合下一轮间隔取决于本轮结果的场景例如心跳、指数退避重试等。以下是一个演示after语义的示意性用法前两次返回Some(500 * Duration.millisecond)第三次返回None让 Timer 自动失效import std.sync.{Timer} import std.time.MonoTime main() { let start MonoTime.now() var times 0 Timer.after(Duration.second, { times 1 println(Tick at: ${MonoTime.now() - start}, times ${times}) if (times 3) { None // 返回 NoneTimer 失效并停止调度 } else { Some(500 * Duration.millisecond) // 下次运行前的最小时间间隔设为 500ms } }) sleep(Duration.second * 3) 0 }需要注意的是该示例仅用于说明after的控制流逻辑Task内的times变量访问处于定时器线程与主线程之间若在真实并发场景中需要跨线程共享计数应改用AtomicInt64等原子类型参见下文综合示例以保证数据同步正确性。CatchupStyle 追平策略三种策略的语义与选型重复性任务在Task 执行时间大于设定触发间隔时会产生时间点堆积。CatchupStyle枚举定义了三种追平策略枚举文档public enum CatchupStyle { | Delay | Burst | Skip }策略语义适用场景Burst默认每个任务的开始时间间隔固定当任务执行时间大于设定的任务触发间隔时间时依次执行错过的时间点上的任务直到追平。定时任务之间有先后关系、需要依次执行任务的场景。Delay上一次任务结束与下一次任务开始的时间间隔总是固定的即下一次任务的开始时间 上一次任务的结束时间 设定的任务触发间隔时间。不关心任务开始的时间点需要两次任务执行之间的时间间隔固定的场景。Skip每个任务的开始时间间隔固定当任务执行时间大于设定的任务触发间隔时间时跳过后面错过的时间点以尽快追平。定时任务之间没有先后关系、可以忽略中间任务的场景。style!是命名参数带!后缀默认值为Burst。三种创建重复任务的接口均可通过命名参数指定例如 sync_package_enums.md 中给出的Delay策略示例import std.sync.{Timer, CatchupStyle} import std.time.{MonoTime} main() { let start MonoTime.now() Timer.repeatTimes(3, Duration.second, Duration.second, { println(Tick at: ${MonoTime.now() - start}) }, style: Delay) sleep(Duration.second * 4) 0 }选型建议若任务间存在严格先后依赖如链式数据处理用Burst若只需保证两次任务间隔恒定如周期性采样用Delay若错过的时间点可以丢弃如刷新缓存、定期汇总最新状态用Skip。控制与查询成员cancel、hashCode 与相等比较cancel主动取消定时器public func cancel(): Unit取消该 Timer 后关联 Task 将不再被调度执行。cancel的语义细节sync_package_classes.md如果调用时关联 Task 正在执行不会打断当前运行该函数不会阻塞当前线程调用该函数多次等同于只调用一次。这意味着cancel只负责停止未来调度对正在执行的 Task 采取放行策略因此可以在任意线程安全地调用它来终止重复性任务如repeat创建的定时器。hashCode 与相等比较public func hashCode(): Int64获取 Timer 对象的哈希值返回Int64。此外Timer还通过EquatableTimer提供了两个运算符重载operator func (rhs: Timer): Bool判断当前 Timer 与rhs是否是同一个实例operator func !(rhs: Timer): Bool判断两个 Timer 是否不是同一个实例。注意这是实例同一性比较而非内容相等性比较这与Timer作为任务控制器的语义一致。参数取值范围与异常速查表综合上述 API各参数的有效范围与异常条件汇总如下均以官方文档为准接口参数取值范围异常条件oncedelay[Duration.Min, Duration.Max] Zero立即执行无repeatdelay[Duration.Min, Duration.Max] Zero立即执行interval Zero抛IllegalArgumentExceptionrepeatinterval(Duration.Zero, Duration.Max]同上repeatDuringperiod(Duration.Zero, Duration.Max]period Zero或interval Zero抛异常repeatTimescount(0, Int64.Max]count 0或interval Zero抛异常综合实战一次性 重复性任务的组合示例sync_samples.md 提供了一个同时使用once与repeat的完整可运行示例展示了如何借助AtomicInt8在定时器线程与主线程之间安全地传递计数import std.sync.* main(): Int64 { let count AtomicInt8(0) Timer.once(50 * Duration.millisecond) { println(run only once) count.fetchAdd(1) } let timer Timer.repeat(100 * Duration.millisecond, 200 * Duration.millisecond, { println(run repetitively) count.fetchAdd(10) }) sleep(Duration.second) timer.cancel() sleep(500 * Duration.millisecond) println(count ${count.load()}) 0 }运行结果run only once run repetitively run repetitively run repetitively run repetitively run repetitively count 51结果解读一次性任务在 50ms 后执行一次count加 1重复任务首次触发于 100ms之后每 200ms 触发一次1 秒内共执行 5 次count加 10×5timer.cancel()后不再有新的触发count最终为 51。该示例同时演示了三个关键实践持有Timer引用repeat创建的定时器必须保存返回值才能在其生命周期内调用cancel原子类型跨线程传值定时器 Task 运行在独立的仓颉线程中与主线程共享状态时应使用AtomicInt8/AtomicInt64等原子类型见 AtomicInt64_class.md保证可见性与同步sleep用于主线程等待仓颉并发程序中常用std.time的sleep(Duration)让主线程等待定时器触发完毕Duration相关常量见 Duration_struct.md。生命周期与内存管理要点最后把Timer的生命周期规则归纳为以下四条实践准则避免踩坑创建即运行四个静态工厂方法在调用时即完成初始化并启动无需额外启动操作结束条件三选一Task 执行完毕once/repeatTimes、到达周期上限repeatDuring、主动cancel任一发生即结束调度未取消前不会被 GC由于隐式spawn与单 Task 绑定语义只要 Timer 还在调度其关联 Task 就保证能被执行因此程序退出前对不再需要的重复性定时器应显式cancel以便及时释放资源异常会杀死 TimerTimer 不捕获 Task 异常Task 内任何未捕获异常都会导致该 Timer 失效因此建议在 Task 内部自行try/catch兜底避免一个异常中断整个定时链路。至此你已经掌握了仓颉std.sync定时器的全部核心 API从once的一次性执行到repeat/repeatDuring/repeatTimes的三种重复模式再到after的动态间隔调度与CatchupStyle追平策略选型以及cancel与生命周期管理。相关 API 细节可继续查阅 Timer_class.json机器可读索引与 sync_package_overview.md并发模型背景。赞分享人工智能AI 技能文档开发工具【免费下载链接】DocAgent项目地址https://gitcode.com/Cangjie-SIG/DocAgent点击查看免费下载相关推荐仓颉 std.sync 并发工具实战Atomic、Mutex、Condition 与 Timer 的完整用法与源码解析仓颉 std.sync 并发工具实战Atomic、Mutex、Condition 与 Timer 的完整用法与源码解析 本文以 cangjie_runtime编程语言语言运行时标准库垃圾回收并发编程仓颉语言 std.sync 并发同步实战Atomic、Mutex、Condition 与 Timer 的完整使用指南仓颉语言 std.sync 并发同步实战Atomic、Mutex、Condition 与 Timer 的完整使用指南 导读 本文以仓颉编程语言标准库 std文档知识库教程OpenHarmony云原生架构实战10个Java设计模式赋能微服务弹性伸缩云原生架构实战10个Java设计模式赋能微服务弹性伸缩 在云原生环境中微服务架构需要应对高并发、分布式事务和动态扩展等挑战。Java设计模式为构建弹性微服务人工智能AI 应用本地部署AI Agent交互助手深度研究上一篇Waza 中文去 AI 味改写指南从识味到改写的完整规则与实践下一篇免费手机号码归属地定位工具输入 11 位号码一步在地图上标出城市创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑