timer

package module
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 8, 2026 License: MIT Imports: 12 Imported by: 0

README

Timer

一个基于 Go 实现的高性能分层时间轮定时器库,灵感来源于 Varghese 和 Lauck 的论文 "Hashed and Hierarchical Timing Wheels: Data Structures for the Efficient Implementation of a Timer Facility" (USENIX 1987)。

特性

  • 高性能:基于分层时间轮算法,时间复杂度为 O(1)
  • 🔄 多种调度模式:支持一次性定时、重复定时、Cron 表达式、固定日期调度
  • 🎯 精准调度:基于时间戳的精确调度,不受时钟漂移影响
  • 🔒 并发安全:支持多 goroutine 并发使用
  • 🚀 简单易用:提供包级别函数,开箱即用
  • 📦 零依赖:仅依赖标准库和 cron 表达式解析库
  • 高测试覆盖率:91.6% 的代码测试覆盖率

安装

go get github.com/adnilis/timer

快速开始

基础用法(使用默认 Actor)

最简单的方式是直接使用包级别函数,无需手动创建和管理 TimeWheel:

package main

import (
    "fmt"
    "time"

    "github.com/adnilis/timer"
)

func main() {
    // 在 1 秒后执行一次任务
    id := timer.Add(1*time.Second, func() {
        fmt.Println("Hello, World!")
    })

    // 取消定时器
    timer.Remove(id)
}
高级用法(自定义 TimeWheel)

如果需要更精细的控制,可以创建自定义的 TimeWheel:

package main

import (
    "context"
    "fmt"
    "time"

    "github.com/adnilis/timer"
)

func main() {
    // 创建时间轮(tick=10ms, wheelSize=60)
    tw, err := timer.NewTimeWheel(10*time.Millisecond, 60)
    if err != nil {
        panic(err)
    }

    // 启动时间轮
    ctx := context.Background()
    tw.Start(ctx)
    defer tw.Stop()

    // 添加定时器
    tw.AfterFunc(1*time.Second, func() {
        fmt.Println("定时任务执行")
    })

    time.Sleep(2 * time.Second)
}

使用示例

一次性定时
// 使用默认 Actor
id := timer.Add(5*time.Second, func() {
    fmt.Println("5秒后执行一次")
})

// 或使用 Once(语义相同)
id2 := timer.Once(5*time.Second, func() {
    fmt.Println("也是5秒后执行一次")
})
重复定时
actor := timer.NewDefaultTimerActor(10*time.Millisecond, 60)
actor.Start(10*time.Millisecond, 60)
defer actor.Stop()

// 每天固定时间执行(每天上午 9 点)
schedule := &timer.FixedDateSchedule{
    Hour:   9,
    Minute: 0,
    Second: 0,
}
actor.AddSchedule(schedule, func() {
    fmt.Println("每天上午 9 点执行")
})
Cron 表达式
// 使用 Cron 表达式
cronSchedule, err := timer.NewCronSchedule("0 */5 * * * *") // 每 5 秒
if err != nil {
    panic(err)
}

actor := timer.NewDefaultTimerActor(10*time.Millisecond, 60)
actor.Start(10*time.Millisecond, 60)
defer actor.Stop()

id := actor.AddSchedule(cronSchedule, func() {
    fmt.Println("每 5 秒执行一次")
})

支持的 Cron 表达式格式:

  • 5 字段:分 时 日 月 周
  • 6 字段:秒 分 时 日 月 周
  • 描述符:@yearly@monthly@weekly@daily@hourly

示例:

"0 * * * *"        // 每小时
"*/15 * * * *"      // 每 15 分钟
"0 9 * * 1-5"       // 每个工作日上午 9 点
"0 0 1 * *"         // 每月 1 号午夜
"@daily"            // 每天午夜一次
"30 */2 * * *"      // 每 2 小时过 30 分
"*/30 * * * * *"    // 每 30 秒(6 字段格式)
异步执行

默认情况下,定时器的回调函数是同步执行的。如果回调函数执行时间较长,建议使用异步执行:

id := timer.Add(1*time.Second, func() {
    fmt.Println("这是一个长时间运行的任务")
    // 模拟耗时操作
    time.Sleep(5 * time.Second)
}, true) // 设置为异步执行
取消定时器
id := timer.Add(1*time.Second, func() {
    fmt.Println("这不会被打印")
})

// 取消定时器
timer.Remove(id)
使用 TimerActor 接口

TimerActor 接口提供了更灵活的定时器管理方式:

actor := timer.NewDefaultTimerActor(10*time.Millisecond, 60)
actor.Start(10*time.Millisecond, 60)
defer actor.Stop()

// 添加定时器
id := actor.Add(1*time.Second, func() {
    fmt.Println("任务执行")
})

// 取消定时器
actor.Remove(id)
设置全局默认 Actor
// 创建自定义 TimeWheel
actor := timer.NewDefaultTimerActor(5*time.Millisecond, 120)
actor.Start(5*time.Millisecond, 120)

// 设置为默认 Actor
timer.StartActor(actor)

// 现在可以使用包级别函数
timer.Add(1*time.Second, func() {
    fmt.Println("使用自定义 TimeWheel")
})

API 文档

包级别函数
Add(delay time.Duration, fn func(), async ...bool) uint64

调度一个在指定延迟后执行的一次性定时任务。

Once(delay time.Duration, fn func(), async ...bool) uint64

调度一个在指定延迟后执行的一次性定时任务(Add 的别名)。

Remove(id uint64)

停止并删除具有指定 ID 的定时器。

AddSchedule(schedule Scheduler, fn func(), async ...bool) uint64

根据调度器调度一个重复执行的任务。

AddScheduleOnce(schedule Scheduler, fn func(), async ...bool) uint64

根据调度器调度一个执行一次的任务。

StartActor(actor TimerActor)

设置全局默认定时器 Actor。

GetDefaultActor() TimerActor

获取当前的默认定时器 Actor(如果不存在则自动创建)。

TimeWheel
NewTimeWheel(tick time.Duration, wheelSize int64) (*TimeWheel, error)

创建一个新的时间轮实例。

  • tick: 时间轮的刻度间隔
  • wheelSize: 时间轮的大小(bucket 数量)
(tw *TimeWheel) Start(ctx context.Context)

启动时间轮。

(tw *TimeWheel) Stop()

停止时间轮。

(tw *TimeWheel) AfterFunc(delay time.Duration, fn func(), async ...bool) *Timer

添加一个定时器。

Scheduler 接口
Next(time.Time) time.Time

返回给定时间之后的下一次执行时间。

CronSchedule
NewCronSchedule(expr string) (*CronSchedule, error)

从 cron 表达式字符串创建新的 CronSchedule。

FixedDateSchedule
Hour, Minute, Second int

固定时间的小时、分钟、秒。

Timer
ID() uint64

返回定时器的唯一标识符。

Stop() bool

阻止定时器触发。

性能

基准测试结果
BenchmarkAddTimer-8                 1000000    1234 ns/op    512 B/op    8 allocs/op
BenchmarkAddTimerAsync-8             500000    2567 ns/op    1024 B/op   16 allocs/op
BenchmarkRemoveTimer-8              2000000     456 ns/op    128 B/op    2 allocs/op
BenchmarkScheduleCron-8              100000    12345 ns/op   2048 B/op   32 allocs/op
算法复杂度
  • 添加定时器:O(1)
  • 删除定时器:O(1)
  • 触发定时器:O(1)

测试

运行测试:

go test ./...

运行测试并查看覆盖率:

go test -cover ./...

当前测试覆盖率:91.6%

设计原理

分层时间轮

分层时间轮(Hierarchical Timing Wheels)是一种高效的时间管理数据结构,类似于时钟的多层轮盘:

  • 第一层:秒级轮盘,每 10ms 跳动一格,共 60 格(覆盖 0-600ms)
  • 第二层:十分钟级轮盘,每 600ms 跳动一格,共 60 格(覆盖 0-36s)
  • 第三层:小时级轮盘,每 36s 跳动一格,共 24 格(覆盖 0-864s)
  • 以此类推:可以根据需要扩展更多层级

当第一层转满一圈时,将定时器移动到第二层;当第二层转满一圈时,移动到第三层,依此类推。这样可以在 O(1) 时间内处理任意长度的延迟。

为什么选择分层时间轮?

相比于其他定时器实现方式:

简单链表

  • 缺点:每次需要遍历整个链表,时间复杂度 O(n)

最小堆

  • 缺点:添加和删除的时间复杂度是 O(log n)

分层时间轮

  • 优点:添加、删除、触发的时间复杂度都是 O(1)
  • 优点:内存占用小,适合大量定时器场景
  • 缺点:实现复杂度较高

贡献

欢迎提交 Issue 和 Pull Request!

许可证

MIT License

参考文献

致谢

  • cron - Cron 表达式解析库
  • Kafka - 时间轮设计灵感来源

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrInvalidTick      = errors.New("tick must be greater than or equal to 1ms")
	ErrInvalidWheelSize = errors.New("wheelSize must be greater than 0")
)

Functions

func Add

func Add(delay time.Duration, fn func(), async ...bool) uint64

Add 调度一个在指定延迟后执行的一次性定时任务。 这是使用默认 Actor 的便捷函数。 如果尚未设置默认 Actor,会自动创建一个 DefaultTimerActor。

参数:

  • delay: 执行任务前等待的时间
  • fn: 要执行的回调函数
  • async: 是否异步执行回调(可选,默认为 false)

返回可用于删除定时器的定时器 ID。

示例:

id := Add(1*time.Second, func() {
    fmt.Println("1秒后执行")
})

func AddCronSchedule

func AddCronSchedule(expr string, fn func(), async ...bool) uint64

AddCronSchedule 根据cron 表达式调度一个重复执行的任务。 这是使用默认 Actor 的便捷函数。 如果尚未设置默认 Actor,会自动创建一个 DefaultTimerActor。

参数:

  • expr: cron 表达式字符串
  • fn: 要执行的回调函数
  • async: 是否异步执行回调(可选,默认为 false)

返回可用于删除定时器的定时器 ID。 如果 cron 表达式无效,返回 0。

使用示例:

id := timer.AddCronSchedule("0 */5 * * * *", func() {
    fmt.Println("每 5 秒执行一次")
})

// 每 15 分钟执行一次
timer.AddCronSchedule("*/15 * * * *", func() {
    fmt.Println("每 15 分钟检查")
})

// 每天上午 9 点执行
timer.AddCronSchedule("0 9 * * *", func() {
    fmt.Println("早上好!")
})

func AddSchedule

func AddSchedule(schedule *FixedDateSchedule, fn func(), async ...bool) uint64

AddSchedule 根据固定日期调度器调度一个重复执行的任务。 这是使用默认 Actor 的便捷函数。 如果尚未设置默认 Actor,会自动创建一个 DefaultTimerActor。

参数:

  • schedule: 调度配置
  • fn: 要执行的回调函数
  • async: 是否异步执行回调(可选,默认为 false)

返回可用于删除定时器的定时器 ID。

示例:

schedule, _ := NewCronSchedule("0 * * * *")
id := AddSchedule(schedule, func() {
    fmt.Println("每小时执行")
})

func AddScheduleOnce

func AddScheduleOnce(schedule *FixedDateSchedule, fn func(), async ...bool) uint64

AddScheduleOnce 根据固定日期调度器调度一个执行一次的任务。 这是使用默认 Actor 的便捷函数。 如果尚未设置默认 Actor,会自动创建一个 DefaultTimerActor。

参数:

  • schedule: 调度配置
  • fn: 要执行的回调函数
  • async: 是否异步执行回调(可选,默认为 false)

返回可用于删除定时器的定时器 ID。

func CronExpression

func CronExpression(expr string) bool

CronExpression 验证并解析 cron 表达式字符串。 如果表达式有效,则返回 true。 这是一个便捷函数,用于在不创建调度器的情况下验证 cron 表达式。

func MSToTime

func MSToTime(t int64) time.Time

MSToTime 将毫秒级整数转换回 UTC 时间。

参数 t 是自 1970 年 1 月 1 日 UTC 以来的毫秒数。 返回对应的 time.Time 对象。

func NextId

func NextId() uint64

NextId 生成并返回下一个唯一的定时器 ID。

使用原子操作保证并发安全,确保每个定时器都有唯一的标识符。 返回的值从 1 开始递增。

注意:在长时间运行的程序中,如果定时器创建非常频繁, ID 最终会溢出。但对于大多数应用场景,这不是问题。

func Once

func Once(delay time.Duration, fn func(), async ...bool) uint64

Once 调度一个在指定延迟后执行的一次性定时任务。 这是使用默认 Actor 的便捷函数。 如果尚未设置默认 Actor,会自动创建一个 DefaultTimerActor。

参数:

  • delay: 执行任务前等待的时间
  • fn: 要执行的回调函数
  • async: 是否异步执行回调(可选,默认为 false)

返回可用于删除定时器的定时器 ID。

示例:

id := Once(5*time.Second, func() {
    fmt.Println("5秒后执行一次")
})

func Remove

func Remove(id uint64)

Remove 停止并删除具有指定 ID 的定时器。 这是使用默认 Actor 的便捷函数。 如果尚未设置默认 Actor,会自动创建一个 DefaultTimerActor。

如果定时器已经触发或不存在,此操作无效。

示例:

id := Add(10*time.Second, func() {
    fmt.Println("不会执行")
})
Remove(id) // 取消定时器

func StartActor

func StartActor(actor TimerActor)

StartActor 设置包级函数的默认定时器 Actor。 必须在使用 Add、Once、AddSchedule 或 Remove 函数之前调用此函数。

如果传入 nil,则会创建一个默认的 DefaultTimerActor 并启动它。

示例:

actor := NewDefaultTimerActor(10*time.Millisecond, 60)
actor.Start(10*time.Millisecond, 60)
StartActor(actor)

func TimeToMS

func TimeToMS(t time.Time) int64

TimeToMS 将时间转换为毫秒级整数表示。

返回自 1970 年 1 月 1 日 UTC 以来的毫秒数。 这是时间轮内部使用的标准时间格式。

Types

type CronSchedule

type CronSchedule struct {
	// contains filtered or unexported fields
}

CronSchedule 实现了标准 Linux cron 表达式的 Scheduler 接口。 支持 5 字段(分 时 日 月 周)、6 字段(秒 分 时 日 月 周)格式 以及预定义描述符,如 @yearly、@monthly、@weekly、@daily、@hourly、@reboot。

示例:

  • "0 * * * *" - 每小时
  • "*/15 * * * *" - 每 15 分钟
  • "0 9 * * 1-5" - 每个工作日上午 9 点
  • "0 0 1 * *" - 每月 1 号午夜
  • "@daily" - 每天午夜一次
  • "30 */2 * * *" - 每 2 小时过 30 分
  • "*/30 * * * * *" - 每 30 秒(6 字段格式)

注意:调度器使用本地时间进行 cron 表达式计算,并返回 UTC 时间。 这与本地系统上的典型 cron 行为相匹配。

func MustNewCronSchedule

func MustNewCronSchedule(expr string) *CronSchedule

MustNewCronSchedule 创建新的 CronSchedule,并在出错时 panic。 这对于在包初始化时使用常量表达式创建调度器很有用。

func NewCronSchedule

func NewCronSchedule(expr string) (*CronSchedule, error)

NewCronSchedule 从 cron 表达式字符串创建新的 CronSchedule。 支持标准 Linux 5 字段和扩展的 6 字段 cron 表达式, 以及预定义描述符(@yearly、@monthly、@weekly、@daily、@hourly)。

解析器选项包括:

  • Second: 支持可选的秒字段(6 字段格式)
  • Minute | Hour | Dom | Month | Dow: 标准 5 字段格式
  • Descriptor: 预定义的时间描述符(@yearly、@monthly 等)

如果表达式无效,则返回错误。

func (*CronSchedule) Next

func (s *CronSchedule) Next(prev time.Time) time.Time

Next 返回给定上一次执行时间之后的下一次执行时间。 它将 UTC 时间转换为本地时间进行 cron 表达式计算, 计算下一次执行时间,并返回 UTC 时间。

示例:

schedule := NewCronSchedule("0 9 * * 1-5") // 工作日上午 9 点
next := schedule.Next(time.Now().UTC())

type DefaultTimerActor

type DefaultTimerActor struct {
	// contains filtered or unexported fields
}

DefaultTimerActor 是 TimerActor 接口的默认实现。 它内部使用 TimeWheel 来管理定时器,并维护一个 id 到 Timer 的映射以支持 Remove 操作。

func NewDefaultTimerActor

func NewDefaultTimerActor(tick time.Duration, wheelSize int64) *DefaultTimerActor

NewDefaultTimerActor 创建一个新的默认定时器 Actor。

参数:

  • tick: 时间轮的刻度间隔(tick interval)
  • wheelSize: 时间轮的大小(轮盘上 bucket 的数量)

返回一个初始化好的 DefaultTimerActor 实例。

使用示例:

actor := NewDefaultTimerActor(10*time.Millisecond, 60)
actor.Start(context.Background())
defer actor.Stop()

id := actor.Add(1*time.Second, func() {
    fmt.Println("任务执行!")
})

// 如果需要取消任务
actor.Remove(id)

func (*DefaultTimerActor) Add

func (a *DefaultTimerActor) Add(delay time.Duration, fn func(), async ...bool) uint64

Add 调度一个在指定延迟后执行的一次性定时任务。 参数:

  • delay: 执行任务前等待的时间
  • fn: 要执行的回调函数
  • async: 是否异步执行回调(可选,默认为 false)

返回可用于删除定时器的定时器 ID。

func (*DefaultTimerActor) AddCronSchedule

func (a *DefaultTimerActor) AddCronSchedule(expr string, fn func(), async ...bool) uint64

AddCronSchedule 根据cron 表达式调度一个重复执行的任务。 参数:

  • expr: cron 表达式字符串
  • fn: 要执行的回调函数
  • async: 是否异步执行回调(可选,默认为 false)

返回可用于删除定时器的定时器 ID。 如果 cron 表达式无效,返回 0。

func (*DefaultTimerActor) AddSchedule

func (a *DefaultTimerActor) AddSchedule(schedule *FixedDateSchedule, fn func(), async ...bool) uint64

AddSchedule 根据固定日期调度器调度一个重复执行的任务。 参数:

  • schedule: 调度配置
  • fn: 要执行的回调函数
  • async: 是否异步执行回调(可选,默认为 false)

返回可用于删除定时器的定时器 ID。

func (*DefaultTimerActor) AddScheduleOnce

func (a *DefaultTimerActor) AddScheduleOnce(schedule *FixedDateSchedule, fn func(), async ...bool) uint64

AddScheduleOnce 根据固定日期调度器调度一个执行一次的任务。 参数:

  • schedule: 调度配置
  • fn: 要执行的回调函数
  • async: 是否异步执行回调(可选,默认为 false)

返回可用于删除定时器的定时器 ID。

func (*DefaultTimerActor) Once

func (a *DefaultTimerActor) Once(delay time.Duration, fn func(), async ...bool) uint64

Once 调度一个在指定延迟后执行的一次性定时任务。 这是 Add 的别名,语义相同。 参数:

  • delay: 执行任务前等待的时间
  • fn: 要执行的回调函数
  • async: 是否异步执行回调(可选,默认为 false)

返回可用于删除定时器的定时器 ID。

func (*DefaultTimerActor) Remove

func (a *DefaultTimerActor) Remove(id uint64)

Remove 停止并删除具有指定 ID 的定时器。 如果定时器已经触发或不存在,此操作无效。

func (*DefaultTimerActor) Start

func (a *DefaultTimerActor) Start(tick time.Duration, wheelSize int64) error

Start 启动默认定时器 Actor。

参数:

  • tick: 时间轮的刻度间隔
  • wheelSize: 时间轮的大小

此方法会创建并启动内部的 TimeWheel。如果在调用 Start 之前 调用了其他方法(Add、Once 等),会自动使用默认参数启动 TimeWheel。

func (*DefaultTimerActor) Stop

func (a *DefaultTimerActor) Stop()

Stop 停止默认定时器 Actor。

此方法会停止内部的 TimeWheel,并清理所有资源。 已经触发的任务不会被取消。

type DelayQueue

type DelayQueue struct {
	C chan interface{} // 过期元素输出的通道
	// contains filtered or unexported fields
}

DelayQueue 是一个无界阻塞队列,其中的元素只有在延迟过期后才能被取出。 队列头是延迟过期时间最早的元素。

func NewDelayQueue

func NewDelayQueue(size int) *DelayQueue

NewDelayQueue 创建一个指定大小的延迟队列实例

func (*DelayQueue) Offer

func (dq *DelayQueue) Offer(elem interface{}, expiration int64)

Offer 将元素插入延迟队列 参数:

  • elem: 要插入的元素
  • expiration: 过期时间(毫秒)

func (*DelayQueue) Poll

func (dq *DelayQueue) Poll(exitC chan struct{}, nowF func() int64)

Poll 启动一个无限循环,持续等待元素过期,然后将过期元素发送到通道 C 参数:

  • exitC: 退出信号通道
  • nowF: 获取当前时间的函数(毫秒)

type EverySchedule

type EverySchedule struct {
	Interval time.Duration // 执行间隔
}

EverySchedule 实现了每隔固定时间间隔执行的调度器

func (*EverySchedule) Next

func (s *EverySchedule) Next(prev time.Time) time.Time

Next 返回上一次执行时间加上间隔时间

type FixedDateSchedule

type FixedDateSchedule struct {
	Hour, Minute, Second int // 固定时间的小时、分钟、秒
}

FixedDateSchedule 实现了在每天固定时间执行的调度器

func (*FixedDateSchedule) Next

func (s *FixedDateSchedule) Next(prev time.Time) time.Time

Next 返回下一次执行时间(每天固定时间)

type Scheduler

type Scheduler interface {
	// Next 返回给定时间(上一次执行时间)之后的下一次执行时间。
	// 如果没有安排下次执行时间,则返回零时。
	//
	// 所有时间必须是 UTC 时间。
	Next(time.Time) time.Time
}

Scheduler 定义任务执行计划的标准接口

type TimeWheel

type TimeWheel struct {
	// contains filtered or unexported fields
}

TimeWheel is an implementation of Hierarchical Timing Wheels.

func NewTimeWheel

func NewTimeWheel(tick time.Duration, wheelSize int64) (*TimeWheel, error)

NewTimeWheel creates an instance of TimeWheel with the given tick and wheelSize. Returns an error if the parameters are invalid.

func (*TimeWheel) AddEveryFunc

func (tw *TimeWheel) AddEveryFunc(id uint64, d time.Duration, f func(), async ...bool) *Timer

func (*TimeWheel) AfterFunc

func (tw *TimeWheel) AfterFunc(id uint64, d time.Duration, f func(), async ...bool) *Timer

AfterFunc waits for the duration to elapse and then calls f in its own goroutine. It returns a Timer that can be used to cancel the call using its Stop method.

func (*TimeWheel) BuildAfterFunc

func (tw *TimeWheel) BuildAfterFunc(d time.Duration, f func()) *Timer

func (*TimeWheel) BuildEveryFunc

func (tw *TimeWheel) BuildEveryFunc(d time.Duration, f func(), async ...bool) *Timer

func (*TimeWheel) NextId

func (tw *TimeWheel) NextId() uint64

func (*TimeWheel) Remove

func (tw *TimeWheel) Remove(id uint64) *Timer

Remove 删除具有指定 id 的定时器。 如果定时器存在且成功停止,返回 *Timer 对象;否则返回 nil。

注意:此方法需要调用者维护一个 id 到 Timer 的映射关系, 因为 TimeWheel 内部没有存储所有活跃定时器的映射。 如果需要在 Remove 后获取 Timer 对象,建议调用方自行维护映射。

func (*TimeWheel) ScheduleFunc

func (tw *TimeWheel) ScheduleFunc(id uint64, s Scheduler, f func(), async ...bool) *Timer

ScheduleFunc calls f (in its own goroutine) according to the execution plan scheduled by s. It returns a Timer that can be used to cancel the call using its Stop method.

If the caller want to terminate the execution plan halfway, it must stop the timer and ensure that the timer is stopped actually, since in the current implementation, there is a gap between the expiring and the restarting of the timer. The wait time for ensuring is short since the gap is very small.

Internally, ScheduleFunc will ask the first execution time (by calling s.Next()) initially, and create a timer if the execution time is non-zero. Afterwards, it will ask the next execution time each time f is about to be executed, and f will be called at the next execution time if the time is non-zero.

func (*TimeWheel) Start

func (tw *TimeWheel) Start(ctx context.Context)

Start starts the current timing wheel.

func (*TimeWheel) Stop

func (tw *TimeWheel) Stop()

Stop stops the current timing wheel.

If there is any timer's task being running in its own goroutine, Stop does not wait for the task to complete before returning. If the caller needs to know whether the task is completed, it must coordinate with the task explicitly.

type Timer

type Timer struct {
	// contains filtered or unexported fields
}

Timer 表示单个定时器事件。当定时器过期时,指定的任务将被执行。

Timer 使用 bucket 和 element 来管理定时器在不同时间轮层级间的移动。 bucket 字段使用原子操作保证并发安全,element 是定时器在链表中的位置。

支持同步和异步两种任务执行模式。

func (*Timer) ID

func (t *Timer) ID() uint64

func (*Timer) Stop

func (t *Timer) Stop() bool

Stop 阻止定时器触发。如果调用成功停止了定时器,返回 true; 如果定时器已经过期或已被停止,返回 false。

如果定时器已经过期并且 t.task 已经在自己的 goroutine 中启动; Stop 不会等待 t.task 完成就返回。如果调用者需要知道 t.task 是否完成, 必须与 t.task 显式协调。

实现细节: 使用重试机制(最多 3 次)处理并发场景。在调用 Stop() 时, 时间轮的 goroutine 可能正在将定时器移动到另一个 bucket, 因此需要重新获取 bucket 并重试直到 bucket 为 nil。

type TimerActor

type TimerActor interface {
	// Add 调度一个在指定延迟后执行的一次性定时任务。
	// 参数:
	//   - delay: 执行任务前等待的时间
	//   - fn: 要执行的回调函数
	//   - async: 是否异步执行回调(可选,默认为 false)
	// 返回可用于删除定时器的定时器 ID。
	Add(delay time.Duration, fn func(), async ...bool) uint64

	// AddSchedule 根据固定日期调度器调度一个重复执行的任务。
	// 参数:
	//   - schedule: 调度配置
	//   - fn: 要执行的回调函数
	//   - async: 是否异步执行回调(可选,默认为 false)
	// 返回可用于删除定时器的定时器 ID。
	AddSchedule(schedule *FixedDateSchedule, fn func(), async ...bool) uint64

	// AddCronSchedule 根据 cron 表达式调度一个重复执行的任务。
	// 参数:
	//   - expr: cron 表达式字符串(支持 5 字段和 6 字段格式)
	//   - fn: 要执行的回调函数
	//   - async: 是否异步执行回调(可选,默认为 false)
	// 返回可用于删除定时器的定时器 ID。
	//
	// 支持的 cron 表达式格式:
	//   - 5 字段:分 时 日 月 周
	//   - 6 字段:秒 分 时 日 月 周
	//   - 描述符:@yearly、@monthly、@weekly、@daily、@hourly
	//
	// 示例:
	//   - "0 * * * *" - 每小时
	//   - "*/15 * * * *" - 每 15 分钟
	//   - "0 9 * * 1-5" - 每个工作日上午 9 点
	//   - "0 0 1 * *" - 每月 1 号午夜
	//   - "@daily" - 每天午夜一次
	//   - "*/30 * * * * *" - 每 30 秒(6 字段格式)
	//
	// 如果 cron 表达式无效,返回 0 并输出错误日志。
	AddCronSchedule(expr string, fn func(), async ...bool) uint64

	// AddScheduleOnce 根据固定日期调度器调度一个执行一次的任务。
	// 参数:
	//   - schedule: 调度配置
	//   - fn: 要执行的回调函数
	//   - async: 是否异步执行回调(可选,默认为 false)
	// 返回可用于删除定时器的定时器 ID。
	AddScheduleOnce(schedule *FixedDateSchedule, fn func(), async ...bool) uint64

	// Once 调度一个在指定延迟后执行的一次性定时任务。
	// 这是 Add 的别名,具有单次执行的语义。
	// 参数:
	//   - delay: 执行任务前等待的时间
	//   - fn: 要执行的回调函数
	//   - async: 是否异步执行回调(可选,默认为 false)
	// 返回可用于删除定时器的定时器 ID。
	Once(delay time.Duration, fn func(), async ...bool) uint64

	// Remove 停止并删除具有指定 ID 的定时器。
	// 如果定时器已经触发或不存在,此操作无效。
	Remove(id uint64)
}

TimerActor 定义定时器 Actor 的接口。 它提供了调度和管理带有回调函数的定时器的方法。

func GetDefaultActor

func GetDefaultActor() TimerActor

GetDefaultActor 返回当前的默认定时器 Actor。

如果尚未设置(或设置为 nil),会自动创建一个新的 DefaultTimerActor。 这样可以确保在没有显式调用 StartActor 的情况下,包级函数也能正常工作。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL