我如何保持长时间运行的Go程序,运行? [英] How best do I keep a long running Go program, running?

查看:623
本文介绍了我如何保持长时间运行的Go程序,运行?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我用Go编写了一个长时间运行的服务器。主程序会执行程序逻辑的几个例程。之后,主没有任何用处。一旦主要退出,程序将退出。我现在用来保持程序运行的方法只是对fmt.Scanln()的简单调用。我想知道其他人如何避免主要退出。以下是一个基本的例子。在这里可以使用什么想法或最佳实践?



我考虑创建一个频道,并通过在所述频道上接收延迟退出主播,但我认为如果全部我的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)
}
}


解决方案Go的运行时的当前设计假定程序员负责检测何时终止一个goroutine和什么时候终止程序。程序员需要计算goroutines和整个程序的终止条件。程序可以通过调用 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆