Golang中的Ticker和Daemon

huangapple go评论73阅读模式
英文:

Ticker and Daemon on Golang

问题

使用Ticker来实现长时间运行的守护进程的优雅终止是可能的吗?我在这里阅读了其他相关的讨论,它指出为了避免内存泄漏,你应该始终关闭通道。但是,如果我以守护进程模式运行它(假设我使用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.")
        // 不能返回,需要继续运行
    }
  }
}

请注意,我只提供翻译服务,不会回答关于翻译内容的问题。

英文:

Is it possible to use Ticker to implemented the graceful termination of a long running daemon process? I read the other related thread on here that you should always close the channel to avoid memory leak, but if I run this in a daemon mode (let said I use daemonize to handle the daemon operation outside of golang), and there's really no way for it to do any collective cleanup before the process is terminated. Unless I'm missing something, I'm here to ask whether there's an alternative/better to do this in Golang

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

答案1

得分: 3

我不确定我完全理解你的目标,但是你可以使用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.")
            // 不能返回,需要继续运行
        case <-death:
            // 进行任何必要的清理操作,然后返回
        }
    }
}

请注意,这只是代码的翻译部分,我无法回答关于代码的问题。

英文:

I'm not sure I fully understand your goal, however you could always use 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 &lt;-ticker.C:
			log.Println(&quot;Scheduled task is triggered.&quot;, t)
			go runWorker(workers)
		case &lt;-workers:
			log.Println(&quot;Scheduled task is completed.&quot;)
			// can&#39;t return, it needs to be continue running
		case &lt;- death:
			//do any clean up you need and return
		}
	}
}

答案2

得分: 1

你的主要函数在每次滴答后读取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.")
        // 不能返回,需要继续运行
    }
  }
}

这样将在每个间隔之后继续创建一个goroutine。直到循环结束之前,你不需要关闭这个通道。如果你的应用程序只是退出,那么通道会被安全地清理。如果你需要提前停止循环,只需在退出循环之前调用ticker.Stop()。

如果你只想在间隔之后运行一次goroutine,可以使用time.AfterFunc函数。

英文:

Your main function reads the ticker channel twice, once after a tick and then again after another tick before proceeding, which is probably not what you want (if Interval was 30 minutes then you would only run a goroutine every 60 minutes). This would be a better approach:

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

  for {
    select {
      case &lt;- ticker.C:
        log.Println(&quot;Scheduled task is triggered.&quot;, t)
        go runWorker(workers)
      case &lt;- workers:
        log.Println(&quot;Scheduled task is completed.&quot;)
        // can&#39;t return, it needs to be continue running
    }
  }
}

This will continue creating a goroutine after each interval. You don't need to close this channel until your loop is finished. If your application just exits then your channel will be cleaned up safely. If you need to stop the loop early then just make sure to call ticker.Stop() before you exit the loop.

If you just want to run a goroutine once after an interval, use time.AfterFunc

huangapple
  • 本文由 发表于 2014年8月2日 09:22:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/25090768.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定