Go 项目的主要 goroutine 永远睡觉?

Go project's main goroutine sleep forever?

有没有API让main协程永远休眠?

换句话说,我希望我的项目始终运行,除非我停止它。

“睡觉”

您可以使用许多永远阻塞的结构,而不会“吃掉”您的 CPU。

例如 select 没有任何 case(也没有 default):

select{}

或者从一个没有人发送任何东西的频道接收:

<-make(chan int)

或者从 nil 频道接收也会永远阻塞:

<-(chan int)(nil)

或者在 nil 频道上发送也会永远阻塞:

(chan int)(nil) <- 0

或锁定一个已经锁定的 sync.Mutex:

mu := sync.Mutex{}
mu.Lock()
mu.Lock()

正在退出

如果您确实想提供一种退出方式,一个简单的渠道就可以做到。提供一个 quit 频道,并从中接收。当你想退出时,关闭 quit 通道,因为“关闭通道上的接收操作总是可以立即进行,在收到任何先前发送的值后产生元素类型的 zero value”。

var quit = make(chan struct{})

func main() {
    // Startup code...

    // Then blocking (waiting for quit signal):
    <-quit
}

// And in another goroutine if you want to quit:
close(quit)

请注意,发出 close(quit) 可能会随时终止您的应用程序。引用自 Spec: Program execution:

Program execution begins by initializing the main package and then invoking the function main. When that function invocation returns, the program exits. It does not wait for other (non-main) goroutines to complete.

close(quit)执行时,我们main()函数的最后一条语句可以继续执行,这意味着main goroutine可以return,所以程序退出。

睡觉不堵

上面的构造阻塞了 goroutine,所以如果你没有其他 goroutines 运行ning,那将导致死锁。

如果你不想阻塞 main goroutine 但你只是不想它结束,你可以使用一个 time.Sleep() 具有足够长的持续时间。最大持续时间值为

const maxDuration time.Duration = 1<<63 - 1

大约是 292 年。

time.Sleep(time.Duration(1<<63 - 1))

如果您担心您的应用 运行 超过 292 年,请将上述休眠置于无限循环中:

for {
    time.Sleep(time.Duration(1<<63 - 1))
}

根据使用情况选择您想要的睡眠类型。

@icza 提供了一个很好的简单的解决方案,可以让你永远休眠,但如果你想让你的系统正常关机,我想再给你一些甜头。

你可以这样做:

func mainloop() {
    exitSignal := make(chan os.Signal)
    signal.Notify(exitSignal, syscall.SIGINT, syscall.SIGTERM)
    <-exitSignal

    systemTeardown()
}

在你的主要部分:

func main() {
    systemStart()
    mainloop()
}

通过这种方式,您不仅可以让您的 main 永远休眠,还可以在您的代码收到来自 OS 的 INTTERM 信号后做一些优雅的关机操作, 比如 ctrl+Ckill.

阻塞goroutine的另一种解决方案。此解决方案可防止 Go-Runtime 抱怨死锁:

import "time"

func main() {
    for {
        time.Sleep(1138800 * time.Hour)
    }
}