Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

增加 func (tw *TimingWheel) EveryFunc(d time.Duration, f func()) *Timer 方法 #8

Closed
Allenxuxu opened this issue Sep 20, 2019 · 7 comments

Comments

@Allenxuxu
Copy link
Contributor

Allenxuxu commented Sep 20, 2019

大佬,考虑增加 定时任务 的接口吗

Pull requests : #9

@RussellLuo
Copy link
Owner

RussellLuo commented Sep 21, 2019

@Allenxuxu 谢谢关注!

基本原则

我希望这个库能够做到最简化:只提供最基本的、必不可少的 API(功能)。不同的应用场景(use cases),可以通过组合使用基本功能来达成目标。

解决思路

这里提到的想要实现 “定时任务”,可以用 AfterFunc 来模拟:即每次执行 f 后,再把 f 重新加入时间轮。

具体有两种实现方式:

1. 每次创建新的 Timer

// tw := timingwheel.NewTimingWheel(...)
// tw.Start()
// defer tw.Stop()

var f fun()
f = func() {
    // main handling logic
    // ...

    tw.AfterFunc(time.Second, f)
}
tw.AfterFunc(time.Second, f)

2. 复用已有的 Timer

第 1 种方式的问题是,会增加 GC 的负担:因为每次重复执行任务时,会创建一个新的 Timer,老的 Timer 等待 GC 回收。

有两种方式可以复用已有的 Timer:

a) 新增一个特定 API

即针对 “定时任务” 的特殊场景,新增一个专门的 API(就是你的 PR 里的 EveryFunc)。但是这种特殊的 API 只能用于 “定时任务”,别的应用场景无法复用,所以违背了上述「基本原则」。

b) 新增一个通用 API

有一种满足「基本原则」的方式,是新增一个 Reset 方法(类似 time 标准库的 Timer.Reset ),任何需要重置 timer 的地方都可以使用。

如果新增了 Reset 方法,“定时任务” 的实现代码变为:

// tw := timingwheel.NewTimingWheel(...)
// tw.Start()
// defer tw.Stop()

var t *timingwheel.Timer
t = tw.AfterFunc(time.Second, func() {
    // main handling logic
    // ...

    // Reset t
})

这里写成 //Reset t 形式,是因为 Reset 的具体实现方式还没有确定。欢迎在这里一起讨论:#10

结论

  • 目前已有的 API,可以做到第 1 种。
  • 作为优化(复用已有的 Timer),我倾向于实现第 2 种的 b) 方式。

@Allenxuxu 你的建议呢?

@Allenxuxu
Copy link
Contributor Author

@RussellLuo 感谢🙏大佬如此深入的回答!

对于 方案 1 每次创建新的 Timer ,这样肯定是不能用来实现”定时任务“的,因为无法通过返回 timer 去关闭定时器(使用者通过封装也是可以的,但是太繁琐了)

方案 2 的 b 实现 Timer.Reset ,我认为很好,通过简单的封装,可以实现”定时任务“ 。但是既然使用者需要“定时任务”接口,为什么还要他每次使用都去复制粘贴一遍呢。库中来封装好它,也不会增加复杂度,还可以提高易用性。

个人建议,Timer.Reset 接口需要,“定时任务”接口也可以封装好提供。

@RussellLuo
Copy link
Owner

但是既然使用者需要“定时任务”接口,为什么还要他每次使用都去复制粘贴一遍呢。库中来封装好它,也不会增加复杂度,还可以提高易用性。

你说得有道理 👍

这个库之前没有考虑过要支持 “定时任务” 的概念,所以我想的是增加 Reset 接口,可以顺便辅助实现 “定时任务”;如果这个库的定位本身就需要支持 “定时任务”,那增加一个专门的 API 无疑是最佳选择。

至于 “timingwheel 是否要支持定时任务,以及应该以怎样的形式支持“,最近比较忙,给我点时间再考虑考虑 :-)

@RussellLuo
Copy link
Owner

RussellLuo commented Sep 25, 2019

@Allenxuxu 我这两天想了下。“定时任务” 本质上是重复性任务(repetitive tasks),而上面讨论的 “每隔固定 interval 执行的任务” 只是重复性任务的其中一种形式。

所以,我考虑在 timingwheel 中增加一种 支持重复性任务的通用机制,从而为实现各种形式的 “定时任务” 提供可能。

详情参考 #11 ,欢迎一起讨论。

@RussellLuo
Copy link
Owner

按照 #11 的设计,目前 timingwheel 已经增加了 ScheduleFunc ,可以支持各种 重复性任务(前提是需要实现 Scheduler)。

因为 重复性任务 形式多样,EveryFunc 代表的 “每隔固定 interval 执行的任务” 只是其中的一种特殊形式,所以 timingwheel 暂时不打算支持这种 特定 API。(不过实现这个功能也很简单,参考 EveryScheduler 的写法。)

@Allenxuxu 因为没有收到你更进一步的反馈,我打算先关闭这个 issue(以及对应的 PR )。如果有更好的建议,也欢迎再提出来一起探讨。再次感谢你的关注和参与!

@Allenxuxu
Copy link
Contributor Author

@RussellLuo 国庆节快乐!

感谢大佬增加 ScheduleFunc !
非常抱歉,没能及时回复消息(白天看过消息准备抽空回复。。。。。 后来一忙又忘记了,实在非常抱歉)。

@RussellLuo
Copy link
Owner

@Allenxuxu 国庆节快乐 🇨🇳 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants