drwo32555 2018-09-18 08:03
浏览 70
已采纳

在Go中间隔并发运行多个功能

I have a list of functions and their respective intervals. I want to run each function at its interval concurrently.

In JavaScript, I wrote something like:

maps.forEach(({fn, interval}) => {
    setInterval(fn, interval)
})

How do I implement this functionality in Golang?

  • 写回答

1条回答 默认 最新

  • douman6679 2018-09-18 08:12
    关注

    Use a time.Ticker to receive "events" periodically, which you may use to time the execution of a function. You may obtain a time.Ticker by calling time.NewTicker(). The returned ticker has a channel on which values are sent periodically.

    Use a goroutine to continuously receive the events and call the function, e.g. with a for range loop.

    Let's see 2 functions:

    func oneSec() {
        log.Println("oneSec")
    }
    
    func twoSec() {
        log.Println("twoSec")
    }
    

    Here's a simple scheduler that periodically calls a given function:

    func schedule(f func(), interval time.Duration) *time.Ticker {
        ticker := time.NewTicker(interval)
        go func() {
            for range ticker.C {
                f()
            }
        }()
        return ticker
    }
    

    Example using it:

    func main() {
        t1 := schedule(oneSec, time.Second)
        t2 := schedule(twoSec, 2*time.Second)
        time.Sleep(5 * time.Second)
        t1.Stop()
        t2.Stop()
    }
    

    Example output (try it on the Go Playground):

    2009/11/10 23:00:01 oneSec
    2009/11/10 23:00:02 twoSec
    2009/11/10 23:00:02 oneSec
    2009/11/10 23:00:03 oneSec
    2009/11/10 23:00:04 twoSec
    2009/11/10 23:00:04 oneSec
    

    Note that Ticker.Stop() does not close the ticker's channel, so a for range will not terminate; Stop() only stops sending values on the ticker's channel.

    If you want to terminate the goroutines used to schedule the function calls, you may do that with an additional channel. And then those goroutines may use a select statement to "monitor" the ticker's channel and this done channel, and return if receiving from done succeeds.

    For example:

    func schedule(f func(), interval time.Duration, done <-chan bool) *time.Ticker {
        ticker := time.NewTicker(interval)
        go func() {
            for {
                select {
                case <-ticker.C:
                    f()
                case <-done:
                    return
                }
            }
        }()
        return ticker
    }
    

    And using it:

    func main() {
        done := make(chan bool)
        t1 := schedule(oneSec, time.Second, done)
        t2 := schedule(twoSec, 2*time.Second, done)
        time.Sleep(5 * time.Second)
        close(done)
        t1.Stop()
        t2.Stop()
    }
    

    Try this one on the Go Playground.

    Note that even though stopping the tickers is not necessary in this simple example (because when the main goroutine ends, so does the program with it), in real-life examples if the app continues to run, leaving the tickers unstopped wastes resources (they will continue to use a background goroutine, and will continue to try to send values on their channels).

    Last words:

    If you have a slice of function-interval pairs, simply use a loop to pass each pair to this schedule() function. Something like this:

    type pair struct {
        f        func()
        interval time.Duration
    }
    
    pairs := []pair{
        {oneSec, time.Second},
        {twoSec, 2 * time.Second},
    }
    
    done := make(chan bool)
    ts := make([]*time.Ticker, len(pairs))
    for i, p := range pairs {
        ts[i] = schedule(p.f, p.interval, done)
    }
    
    time.Sleep(5 * time.Second)
    close(done)
    
    for _, t := range ts {
        t.Stop()
    }
    

    Try this one on the Go Playground.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 在不同的执行界面调用同一个页面
  • ¥20 基于51单片机的数字频率计
  • ¥50 M3T长焦相机如何标定以及正射影像拼接问题
  • ¥15 keepalived的虚拟VIP地址 ping -s 发包测试,只能通过1472字节以下的数据包(相关搜索:静态路由)
  • ¥20 关于#stm32#的问题:STM32串口发送问题,偶校验(even),发送5A 41 FB 20.烧录程序后发现串口助手读到的是5A 41 7B A0
  • ¥15 C++map释放不掉
  • ¥15 Mabatis查询数据
  • ¥15 想知道lingo目标函数中求和公式上标是变量情况如何求解
  • ¥15 关于E22-400T22S的LORA模块的通信问题
  • ¥15 求用二阶有源低通滤波将3khz方波转为正弦波的电路