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 的 INT
或 TERM
信号后做一些优雅的关机操作, 比如 ctrl+C
或 kill
.
阻塞goroutine的另一种解决方案。此解决方案可防止 Go-Runtime 抱怨死锁:
import "time"
func main() {
for {
time.Sleep(1138800 * time.Hour)
}
}
有没有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 的 INT
或 TERM
信号后做一些优雅的关机操作, 比如 ctrl+C
或 kill
.
阻塞goroutine的另一种解决方案。此解决方案可防止 Go-Runtime 抱怨死锁:
import "time"
func main() {
for {
time.Sleep(1138800 * time.Hour)
}
}