【问题标题】:Ticker and Daemon on GolangGolang 上的 Ticker 和守护进程
【发布时间】:2014-09-25 06:42:05
【问题描述】:

是否可以使用 Ticker 实现长时间运行的守护进程的优雅终止?我在here 上阅读了另一个相关线程,您应该始终关闭通道以避免内存泄漏,但是如果我在守护程序模式下运行它(假设我使用daemonize 来处理 golang 之外的守护程序操作),并且在进程终止之前,它真的没有办法进行任何集体清理。除非我遗漏了什么,否则我在这里询问是否有替代/更好的方式在 Golang 中执行此操作

func main() {
  ticker := time.NewTicker(Interval)
  workers := make(chan bool, 1)

  for t := range ticker.C {
    select {
      case <- ticker.C:
        log.Println("Scheduled task is triggered.", t)
        go runWorker(workers)
      case <- workers:
        log.Println("Scheduled task is completed.")
        // can't return, it needs to be continue running
    }
  }
}

【问题讨论】:

    标签: unix go daemon daemons


    【解决方案1】:

    我不确定我是否完全理解您的目标,但您始终可以使用signal.Notify

    func main() {
        ticker := time.NewTicker(Interval)
        workers := make(chan bool, 1)
        death := make(chan os.Signal, 1)
        signal.Notify(death, os.Interrupt, os.Kill)
    
        for {
            select {
            case <-ticker.C:
                log.Println("Scheduled task is triggered.", t)
                go runWorker(workers)
            case <-workers:
                log.Println("Scheduled task is completed.")
                // can't return, it needs to be continue running
            case <- death:
                //do any clean up you need and return
            }
        }
    }
    

    【讨论】:

    • 应该是signal.Notify(death, os.Interrupt, os.Kill) 但是,是的,你完全读懂了我的想法,这就是我需要的!谢谢!你救了我两次! @OneofOne
    • 糟糕,已修复,很高兴为您提供帮助。
    【解决方案2】:

    您的 main 函数两次读取 ticker 通道,一次在一个刻度之后,然后在另一个刻度之后再次读取,然后再继续,这可能不是您想要的(如果 Interval 是 30 分钟,那么您只会每 60 分钟运行一次 goroutine)。这将是一个更好的方法:

    func main() {
      ticker := time.NewTicker(Interval)
      workers := make(chan bool, 1)
    
      for {
        select {
          case <- ticker.C:
            log.Println("Scheduled task is triggered.", t)
            go runWorker(workers)
          case <- workers:
            log.Println("Scheduled task is completed.")
            // can't return, it needs to be continue running
        }
      }
    }
    

    这将在每个间隔之后继续创建一个 goroutine。在循环完成之前,您无需关闭此通道。如果您的应用程序刚刚退出,那么您的频道将被安全清理。如果您需要提前停止循环,请确保在退出循环之前调用ticker.Stop()。

    如果您只想在间隔后运行一次 goroutine,请使用 time.AfterFunc

    【讨论】:

    • 感谢@rauyan,这很有道理!
    猜你喜欢
    • 1970-01-01
    • 2023-03-02
    • 1970-01-01
    • 2011-07-13
    • 1970-01-01
    • 1970-01-01
    • 2014-07-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多