最近在通读 《The Go Programming Language》,真是好书。
读到 gorotuine,想到之前写 javascript 时常常需要一个 poller 轮询一些后台任务的执行结果,其实用 golang 的 gorutine 和 channel 实现可以更简洁而高效。
看代码:
// Intervaler 是个接口用来让调用者自定义poller轮询时间间隔
type Intervaler interface {
Interval() time.Duration
}
// IntervalerFunc 用来将 func() time.Duration 转化成 Intervaler
type IntervalerFunc func() time.Duration
func (intervalerFunc IntervalerFunc) Interval() time.Duration {
return intervalerFunc()
}
type Poller struct {
//要执行的方法
do func() error
//用于调用者传递停止信号
cancle chan int
//下次调用的时间间隔
nextInterval Intervaler
}
// Poll 轮询
func (poller *Poller) Poll() {
for {
select {
case <-poller.cancle:
return
case <-time.After(poller.nextInterval.Interval()):
go func() {
if err := poller.do(); err != nil {
log.Errorf("Poll poller.go: polling method returns a error: %v", err)
// 或者结束整个轮询
// poller.Cancel()
}
}()
}
}
}
// Cancel 向 cancel 发送信号
func (poller *Poller) Cancel() {
println("Polling stopped")
poller.cancle <- 1
}
// NewPoller 创建一个新的 Poller
func NewPoller(intervaler Intervaler, do func() error) *Poller {
return &Poller{do: do, cancle: make(chan int), nextInterval: intervaler}
}
再来看看如何使用:
func main() {
// 自定义 Intervaler
base := time.Second * 0
interval := IntervalerFunc(func() time.Duration {
next := base
base += 500 * time.Millisecond
return next
})
// 创建一个 poller
poller := NewPoller(interval,
func() error {
// 4秒后 输出 ping!
time.AfterFunc(time.Second*4, func() { println("ping!") })
return nil
})
// 5 秒后停止 polling
time.AfterFunc(time.Second*5, poller.Cancel)
// 开始 polling
poller.Poll()
}
输出:
ping!
ping!
Polling stopped
差不多就是这么多了,大家可以根据不同的业务需求灵活自定义 Poller 的细节。