Go项目的主goroutine永远休眠吗?

huangapple go评论95阅读模式
英文:

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:

&lt;-make(chan int)

Or receiving from a nil channel also blocks forever:

&lt;-(chan int)(nil)

Or sending on a nil channel also blocks forever:

(chan int)(nil) &lt;- 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):
    &lt;-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&lt;&lt;63 - 1

which is approximately 292 years.

time.Sleep(time.Duration(1&lt;&lt;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&lt;&lt;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()
}

通过这种方式,你不仅可以让主程序永久休眠,还可以在代码接收到操作系统发送的INTTERM信号(例如ctrl+Ckill)后,执行一些优雅的关闭操作。

英文:

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)
    &lt;-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 &quot;time&quot;

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

huangapple
  • 本文由 发表于 2016年4月5日 14:48:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/36419054.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定