给大家分享一个阻止Go程序退出的方法集合,其中还是有一些脑洞大开的方法。你有什么别的方法可以阻止Go程序退出么,欢迎在留言区留言。
像下面这样的程序,程序一运行就是退出了,原因在于主goroutine执行完了,子goroutine虽然存在,但是没能阻止主goroutine的执行:
1 2 3 4 5 6 7
| package main import "net/http" func main() { go http.ListenAndServe(":8080", nil) }
|
我整理了11个方法,看看你是否想得到。
方法一: 死循环
这个方法是一个傻傻的方法,会耗费一个CPU核空转。
1 2 3 4 5 6 7 8 9 10
| package main import "net/http" func main() { go http.ListenAndServe(":8080", nil) for { } }
|
方法二:select{}
这是我写例子的时候常用的一个技巧,使用不带case的select语句,字数够少,所以我喜欢用。
1 2 3 4 5 6 7 8 9
| package main import "net/http" func main() { go http.ListenAndServe(":8080", nil) select {} }
|
方法三: 从一个不带缓存的channel中读数据或者放数据
两种方法都会被阻塞。
1 2 3 4 5 6 7 8 9 10 11
| package main import "net/http" func main() { go http.ListenAndServe(":8080", nil) c := make(chan struct{}) c <- struct{}{} }
|
方法四: 从一个nil channel中读数据或者放数据
两种方法都会被阻塞。
1 2 3 4 5 6 7 8 9 10 11 12
| package main import "net/http" func main() { go http.ListenAndServe(":8080", nil) var c chan struct{} c <- struct{}{} }
|
方法五:互斥锁
读写锁也类似。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| package main import ( "net/http" "sync" ) func main() { go http.ListenAndServe(":8080", nil) var m sync.Mutex m.Lock() m.Lock() }
|
方法六:WaitGroup
也许你已经掌握套路了,很多同步原语都可以,比如Cond、信号量,我们就不重复介绍了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| package main import ( "net/http" "sync" ) func main() { go http.ListenAndServe(":8080", nil) var wg sync.WaitGroup wg.Add(1) wg.Wait() }
|
方法七: 阻塞I/O
最简单的使用os.Stdin
,还可以使用文件、socket等,只要阻塞I/O即可。
1 2 3 4 5 6 7 8 9 10 11 12
| package main import ( "net/http" "os" ) func main() { go http.ListenAndServe(":8080", nil) os.Stdin.Read(make([]byte, 1)) }
|
方法八: 使用 signal.Notify
这是我在产品中经常使用的一个技巧,捕获os.Signal
,实现优雅的退出。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| package main import ( "net/http" "os" "os/signal" ) func main() { go http.ListenAndServe(":8080", nil) c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt) <-c }
|
方法九: 使用 signal.Notify
的变形
使用Context,可以把context传递给子goroutine,Context也适合和select配套使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| package main import ( "context" "net/http" "os" "os/signal" ) func main() { go http.ListenAndServe(":8080", nil) ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt) defer stop() <-ctx.Done() }
|
方法十: fmt.Scanln()
阻塞I/O更简洁的方式。
1 2 3 4 5 6 7 8 9 10 11 12
| package main import ( "fmt" "net/http" ) func main() { go http.ListenAndServe(":8080", nil) fmt.Scanln() }
|
方法十一: runtime.Goexit()
主程序退出但是函数却不返回,直到子goroutine完成。
1 2 3 4 5 6 7 8 9 10 11 12
| package main import ( "net/http" "runtime" ) func main() { go http.ListenAndServe(":8080", nil) runtime.Goexit() }
|
你还知道哪些方法?