为了账号安全,请及时绑定邮箱和手机立即绑定

如何最好地保持长时间运行的Go程序的运行?

如何最好地保持长时间运行的Go程序的运行?

Go
哔哔one 2021-05-07 14:11:30
我有一个用Go语言编写的运行时间较长的服务器。Main会触发执行程序逻辑的多个goroutine。在那之后主要没有任何用处。一旦主程序退出,程序将退出。我现在使用的使程序运行的方法只是对fmt.Scanln()的简单调用。我想知道其他人如何阻止main退出。以下是一个基本示例。在这里可以使用哪些想法或最佳做法?我考虑过创建一个通道并通过接收该通道来延迟main的退出,但是我认为如果我的所有goroutine在某个时候都变得不活动,那可能会出现问题。旁注:在我的服务器(不是示例)中,该程序实际上并没有连接到Shell上运行,因此无论如何与控制台进行交互都没有任何意义。目前它可以工作,但是我正在寻找“正确”的方法,假设有一种方法。package mainimport (    "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)    }}
查看完整描述

3 回答

?
LEATH

TA贡献1936条经验 获得超6个赞

Go的当前运行时设计假定程序员负责检测何时终止goroutine和何时终止程序。程序员需要计算goroutine以及整个程序的终止条件。可以通过调用os.Exit或从main()函数返回以正常方式终止程序。


main()通过立即在所述通道上接收来创建通道并延迟退出,是一种防止main退出的有效方法。但是它不能解决检测何时终止程序的问题。


如果在main()函数进入等待所有goroutines终止循环之前无法计算goroutine的数量,则需要发送增量,以便main函数可以跟踪正在运行的goroutine的数量:


// 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

}

另一种方法是将频道替换为sync.WaitGroup。这种方法的缺点是wg.Add(int)需要在调用之前先进行调用wg.Wait(),因此必须在其中至少创建一个goroutine,main()然后才能在程序的任何部分中创建后续goroutine:


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()

}


查看完整回答
反对 回复 2021-05-10
?
jeck猫

TA贡献1909条经验 获得超7个赞

Go的运行时程序包具有一个名为的函数runtime.Goexit,该函数可以完全满足您的要求。


从主goroutine调用Goexit会终止该goroutine,而不会返回func main。由于func main尚未返回,因此程序将继续执行其他goroutine。如果所有其他goroutine退出,程序将崩溃。


在操场上的例子


package main


import (

    "fmt"

    "runtime"

    "time"

)


func main() {

    go func() {

        time.Sleep(time.Second)

        fmt.Println("Go 1")

    }()

    go func() {

        time.Sleep(time.Second * 2)

        fmt.Println("Go 2")

    }()


    runtime.Goexit()


    fmt.Println("Exit")

}


查看完整回答
反对 回复 2021-05-10
  • 3 回答
  • 0 关注
  • 376 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信