我如何保持长时间运行的Go程序,运行? [英] How best do I keep a long running Go program, running?
问题描述
我考虑创建一个频道,并通过在所述频道上接收延迟退出主播,但我认为如果全部我的goroutines在某些时候变得无效。
注意:在我的服务器(不是这个例子)中,程序实际上并没有连接到一个shell,所以它不会无论如何,与控制台进行交互确实没什么意义。现在它可行,但我正在寻找正确的方式,假设有一个。
package main
导入(
fmt
时间
)
func main(){
go forever()
//让这个goroutine退出
//这样程序不会结束。
//这是我的问题的焦点。
fmt.Scanln()
}
func forever(){
for; ; {
//一个例子goroutine可能无限期地运行
//。在实际执行中
//它可能会阻塞chanel而不是
// time.Sleep。
fmt.Printf(%v + \\\
,time.Now())
time.Sleep(time.Second)
}
}
os.Exit
或从 main()
函数返回。 创建频道并延迟通过在所述频道上立即接收,退出 main()
是防止退出 main
的有效方法。但是它并没有解决检测何时终止程序的问题。
如果在 main()之前无法计算goroutines的数量, / code>函数进入wait-for-all-goroutines-to-terminate循环,你需要发送deltas以便
main
函数可以跟踪许多goroutines正在运行:
//接收goroutines数量的变化
var goroutineDelta = make(chan int)
func main(){
go forever()
$ b $ numGoroutines:= 0
for diff:= range goroutineDelta {
numGoroutines + = diff
如果numGoroutines == 0 {os.Exit(0)}
}
}
//概念代码
func forever( ){
for {
if needToCreateANewGoroutine {
//请务必在go f()之前执行此操作,而不是在f()内
goroutineDelta< - +1
去f()
}
}
}
func f(){
//当检测到该goroutine的终止条件时,执行:
goroutineDelta< - -1
}
另一种方法是用 sync.WaitGroup
。这种方法的缺点是需要在调用 wg.Wait()
之前调用 wg.Add(int)
,所以有必要在 main()
中创建至少1个goroutine,而随后的goroutine可以在程序的任何部分创建:
var wg sync.WaitGroup
func main(){
//创建至少1个goroutine
wg。添加(1)
去f()
去永远()
wg.Wait()
}
//概念性代码
func forever(){
for {
if needToCreateANewGoroutine {
wg.Add(1)
go f()
}
}
func f(){
//当检测到该goroutine的终止条件时,执行:
wg.Done()
}
I've a long running server written in Go. Main fires off several goroutines where the logic of the program executes. After that main does nothing useful. Once main exits, the program will quit. The method I am using right now to keep the program running is just a simple call to fmt.Scanln(). I'd like to know how others keep main from exiting. Below is a basic example. What ideas or best practices could be used here?
I considered creating a channel and delaying exit of main by receiving on said channel, but I think that could be problematic if all my goroutines become inactive at some point.
Side note: In my server (not the example), the program isn't actually running connected to a shell, so it doesn't really make sense to interact with the console anyway. For now it works, but I'm looking for the "correct" way, assuming there is one.
package main
import (
"fmt"
"time"
)
func main() {
go forever()
//Keep this goroutine from exiting
//so that the program doesn't end.
//This is the focus of my question.
fmt.Scanln()
}
func forever() {
for ; ; {
//An example goroutine that might run
//indefinitely. In actual implementation
//it might block on a chanel receive instead
//of time.Sleep for example.
fmt.Printf("%v+\n", time.Now())
time.Sleep(time.Second)
}
}
The current design of Go's runtime assumes that the programmer is responsible for detecting when to terminate a goroutine and when to terminate the program. The programmer needs to compute the termination condition for goroutines and also for the entire program. A program can be terminated in a normal way by calling os.Exit
or by returning from the main()
function.
Creating a channel and delaying exit of main()
by immediately receiving on said channel is a valid approach of preventing main
from exiting. But it does not solve the problem of detecting when to terminate the program.
If the number of goroutines cannot be computed before the main()
function enters the wait-for-all-goroutines-to-terminate loop, you need to be sending deltas so that main
function can keep track of how many goroutines are in flight:
// Receives the change in the number of goroutines
var goroutineDelta = make(chan int)
func main() {
go forever()
numGoroutines := 0
for diff := range goroutineDelta {
numGoroutines += diff
if numGoroutines == 0 { os.Exit(0) }
}
}
// Conceptual code
func forever() {
for {
if needToCreateANewGoroutine {
// Make sure to do this before "go f()", not within f()
goroutineDelta <- +1
go f()
}
}
}
func f() {
// When the termination condition for this goroutine is detected, do:
goroutineDelta <- -1
}
An alternative approach is to replace the channel with sync.WaitGroup
. A drawback of this approach is that wg.Add(int)
needs to be called before calling wg.Wait()
, so it is necessary to create at least 1 goroutine in main()
while subsequent goroutines can be created in any part of the program:
var wg sync.WaitGroup
func main() {
// Create at least 1 goroutine
wg.Add(1)
go f()
go forever()
wg.Wait()
}
// Conceptual code
func forever() {
for {
if needToCreateANewGoroutine {
wg.Add(1)
go f()
}
}
}
func f() {
// When the termination condition for this goroutine is detected, do:
wg.Done()
}
这篇关于我如何保持长时间运行的Go程序,运行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!