怎麼阻止一個 Go 程序退出?

給大家分享一個阻止 Go 程序退出的方法集合,其中還是有一些腦洞大開的方法。你有什麼別的方法可以阻止 Go 程序退出麼, 歡迎在留言區留言。

像下面這樣的程序,程序一運行就是退出了,原因在於主 goroutine 執行完了,子 goroutine 雖然存在,但是沒能阻止主 goroutine 的執行:

package main

import "net/http"

func main() {
 go http.ListenAndServe(":8080", nil)
}

我整理了 11 個方法,看看你是否想得到。

方法一:死循環

這個方法是一個傻傻的方法,會耗費一個 CPU 核空轉。

package main

import "net/http"

func main() {
 go http.ListenAndServe(":8080", nil)

 for {
 }
}

方法二:select{}

這是我寫例子的時候常用的一個技巧,使用不帶 case 的 select 語句,字數夠少,所以我喜歡用。

package main

import "net/http"

func main() {
 go http.ListenAndServe(":8080", nil)

 select {}
}

方法三: 從一個不帶緩存的 channel 中讀數據或者放數據

兩種方法都會被阻塞。

package main

import "net/http"

func main() {
 go http.ListenAndServe(":8080", nil)

 c := make(chan struct{})
 // <-c
 c <- struct{}{}
}

方法四:從一個 nil channel 中讀數據或者放數據

兩種方法都會被阻塞。

package main

import "net/http"

func main() {
 go http.ListenAndServe(":8080", nil)

 var c chan struct{}
 // <-c

 c <- struct{}{}
}

方法五:互斥鎖

讀寫鎖也類似。

package main

import (
 "net/http"
 "sync"
)

func main() {
 go http.ListenAndServe(":8080", nil)

 var m sync.Mutex
 m.Lock()
 m.Lock()
}

方法六:WaitGroup

也許你已經掌握套路了,很多同步原語都可以,比如 Cond、信號量,我們就不重複介紹了。

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 即可。

package main

import (
 "net/http"
 "os"
)

func main() {
 go http.ListenAndServe(":8080", nil)

 os.Stdin.Read(make([]byte, 1))
}

方法八: 使用 signal.Notify

這是我在產品中經常使用的一個技巧,捕獲os.Signal, 實現優雅的退出。

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 配套使用。

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 更簡潔的方式。

package main

import (
 "fmt"
 "net/http"
)

func main() {
 go http.ListenAndServe(":8080", nil)

 fmt.Scanln()
}

方法十一:runtime.Goexit()

主程序退出但是函數卻不返回,直到子 goroutine 完成。

package main

import (
 "net/http"
 "runtime"
)

func main() {
 go http.ListenAndServe(":8080", nil)

 runtime.Goexit()
}

你還知道哪些方法?

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/C2AmKZjg9CyiIDxyU0-b1Q