英文:
Go project's main goroutine sleep forever?
问题
有没有API可以让main
goroutine永久休眠?
换句话说,我希望我的项目一直运行,除非我停止它。
英文:
Is there any API to let the main
goroutine sleep forever?
In other words, I want my project always run except when I stop it.
答案1
得分: 72
"睡眠"
你可以使用多种构造来阻塞程序而不会占用CPU资源。
例如,使用没有任何case
(也没有default
)的select
语句:
select{}
或者从一个没有发送任何数据的通道接收:
<-make(chan int)
或者从一个nil
通道接收也会永久阻塞:
<-(chan int)(nil)
或者向一个nil
通道发送也会永久阻塞:
(chan int)(nil) <- 0
或者锁定一个已经被锁定的sync.Mutex
:
mu := sync.Mutex{}
mu.Lock()
mu.Lock()
退出
如果你想提供一种退出的方式,可以使用一个简单的通道。提供一个quit
通道,并从中接收数据。当你想退出时,关闭quit
通道,因为“对一个已关闭的通道进行接收操作总是可以立即进行,返回元素类型的零值,在之前发送的值都被接收后”。
var quit = make(chan struct{})
func main() {
// 启动代码...
// 然后阻塞(等待退出信号):
<-quit
}
// 在另一个goroutine中,如果你想退出:
close(quit)
请注意,执行close(quit)
可能会随时终止你的应用程序。引用自规范:程序执行:
程序的执行从初始化主包开始,然后调用函数
main
。当该函数调用返回时,程序退出。它不会等待其他(非main
)goroutine完成。
当执行close(quit)
时,我们的main()
函数的最后一条语句可以继续执行,这意味着main
goroutine 可以返回,从而使程序退出。
无阻塞的睡眠
上述构造会阻塞goroutine,因此如果没有其他goroutine在运行,就会导致死锁。
如果你不想阻塞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))
}
英文:
"Sleeping"
You can use numerous constructs that block forever without "eating" up your CPU.
For example a select
without any case
(and no default
):
select{}
Or receiving from a channel where nobody sends anything:
<-make(chan int)
Or receiving from a nil
channel also blocks forever:
<-(chan int)(nil)
Or sending on a nil
channel also blocks forever:
(chan int)(nil) <- 0
Or locking an already locked sync.Mutex
:
mu := sync.Mutex{}
mu.Lock()
mu.Lock()
Quitting
If you do want to provide a way to quit, a simple channel can do it. Provide a quit
channel, and receive from it. When you want to quit, close the quit
channel as "a receive operation on a closed channel can always proceed immediately, yielding the element type's zero value after any previously sent values have been received".
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)
Note that issuing a close(quit)
may terminate your app at any time. Quoting from 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.
When close(quit)
is executed, the last statement of our main()
function can proceed which means the main
goroutine can return, so the program exits.
Sleeping without blocking
The above constructs block the goroutine, so if you don't have other goroutines running, that will cause a deadlock.
If you don't want to block the main
goroutine but you just don't want it to end, you may use a time.Sleep()
with a sufficiently large duration. The max duration value is
const maxDuration time.Duration = 1<<63 - 1
which is approximately 292 years.
time.Sleep(time.Duration(1<<63 - 1))
If you fear your app will run longer than 292 years, put the above sleep in an endless loop:
for {
time.Sleep(time.Duration(1<<63 - 1))
}
答案2
得分: 8
选择什么样的睡眠方式取决于使用情况。
@icza提供了一个很好且简单的解决方案,可以实现永久睡眠,但如果你希望系统能够优雅地关闭,我可以给你一些更多的建议。
你可以这样做:
func mainloop() {
exitSignal := make(chan os.Signal)
signal.Notify(exitSignal, syscall.SIGINT, syscall.SIGTERM)
<-exitSignal
systemTeardown()
}
func main() {
systemStart()
mainloop()
}
通过这种方式,你不仅可以让主程序永久休眠,还可以在代码接收到操作系统发送的INT
或TERM
信号(例如ctrl+C
或kill
)后,执行一些优雅的关闭操作。
英文:
It depends on use cases to choose what kind of sleep you want.
@icza provides a good and simple solution for literally sleeping forever, but I want to give you some more sweets if you want your system could shutdown gracefully.
You could do something like this:
func mainloop() {
exitSignal := make(chan os.Signal)
signal.Notify(exitSignal, syscall.SIGINT, syscall.SIGTERM)
<-exitSignal
systemTeardown()
}
And in your main:
func main() {
systemStart()
mainloop()
}
In this way, you could not only ask your main to sleep forever, but you could do some graceful shutdown stuff after your code receives INT
or TERM
signal from OS, like ctrl+C
or kill
.
答案3
得分: 0
另一种阻塞goroutine的解决方案。这个解决方案可以防止Go运行时报告死锁:
import "time"
func main() {
for {
time.Sleep(1138800 * time.Hour)
}
}
英文:
Another solution to block a goroutine. This solution prevents Go-Runtime to complain about the deadlock:
import "time"
func main() {
for {
time.Sleep(1138800 * time.Hour)
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论