GOLANG使用Context管理關聯goroutine
一般一個業務很少不用到 goroutine 的,因為很多方法是需要等待的,例如http.Server.ListenAndServe
這個就是等待的,除非關閉了 Server 或 Listener,否則是不會返回的。除非是一個 API 伺服器,否則肯定需要另外起 goroutine 發起其他的服務,而且對於 API 伺服器來說,在http.Handler
的處理函式中一般也需要起 goroutine,如何管理這些 goroutine,在 GOLANG1.7 提供context.Context
。
先看一個簡單的,如果啟動兩個 goroutine,一個是 HTTP,還有個訊號處理的收到退出訊號做清理:
wg := sync.WaitGroup{}
defer wg.Wait()
wg.Add(1)
go func() {
defer wg.Done()
ss := make(os.Signal, 0)
signal.Notify(ss, syscall.SIGINT, syscall.SIGTERM)
for s := ss {
fmt.Println("Got signal", s)
break
}
}()
wg.Add(1)
go func() {
defer wg.Done()
svr := &http.Server{ Addr:":8080", Handler:nil, }
fmt.Println(svr.ListenAndServe())
}
很清楚,起了兩個 goroutine,然後用 WaitGroup 等待它們退出。如果它們之間沒有互動,不互相影響,那真的是蠻簡單的,可惜這樣是不行的,因為訊號的 goroutine 收到退出訊號後,應該通知 server 退出。暴力一點的是直接呼叫svr.Close()
,但是如果有些請求還需要取消怎麼辦呢?最好用 Context 了:
wg := sync.WaitGroup{}
defer wg.Wait()
ctx,cancel := context.WithCancel(context.Background())
wg.Add(1)
go func() {
defer wg.Done()
ss := make(chan os.Signal, 0)
signal.Notify(ss, syscall.SIGINT, syscall.SIGTERM)
select {
case <- ctx.Done():
return
case s := <- ss:
fmt.Println("Got signal", s)
cancel() // 取消請求,通知用到ctx的所有goroutine
return
}
}()
wg.Add(1)
go func() {
defer wg.Done()
defer cancel()
svr := &http.Server{ Addr:":8080", Handler:nil, }
go func(){
select {
case <- ctx.Done():
svr.Close()
}
}
fmt.Println(svr.ListenAndServe())
}
這個方式可以在新開 goroutine 時繼續使用,譬如新加一個 goroutine,裡面讀寫了 UDPConn:
wg.Add(1)
go func() {
defer wg.Done()
defer cancel()
var conn *net.UDPConn
if conn,err = net.Dial("udp", "127.0.0.1:1935"); err != nil {
fmt.Println("Dial UDP server failed, err is", err)
return
}
fmt.Println(UDPRead(ctx, conn))
}()
UDPRead = func(ctx context.Context, conn *net.UDPConn) (err error) {
wg := sync.WaitGroup{}
defer wg.Wait()
ctx, cancel := context.WithCancel(ctx)
wg.Add(1)
go func() {
defer wg.Done()
defer cancel()
for {
b := make([]byte, core.MTUSize)
size, _, err := conn.ReadFromUDP(b)
// 處理UDP包 b[:size]
}
}()
select {
case <-ctx.Done():
conn.Close()
}
return
}
如果只是用到 HTTP Server,可以這麼寫:
func run(ctx contex.Context) {
server := &http.Server{Addr: addr, Handler: nil}
go func() {
select {
case <-ctx.Done():
server.Close()
}
}()
http.HandleFunc("/api", func(w http.ResponseWriter, r *http.Request) {
})
fmt.Println(server.ListenAndServe())
}
如果需要提供一個 API 來讓伺服器退出,可以這麼寫:
func run(ctx contex.Context) {
server := &http.Server{Addr: addr, Handler: nil}
ctx, cancel := context.WithCancel(ctx)
http.HandleFunc("/quit", func(w http.ResponseWriter, r *http.Request) {
cancel() // 使用區域性的ctx和cancel
})
go func() {
select {
case <-ctx.Done():
server.Close()
}
}()
fmt.Println(server.ListenAndServe())
}
使用區域性的 ctx 和 cancel,可以避免 cancel 傳入的 ctx,只是影響當前的 ctx。
更多原創文章乾貨分享,請關注公眾號
- 加微信實戰群請加微信(註明:實戰群):gocnio
相關文章
- 關於golang的goroutine schedulerGolang
- Golang中context使用GolangContext
- 學會使用context取消goroutine執行的方法ContextGo
- [Golang基礎]GoroutineGolang
- golang中的context包GolangContext
- Golang Context 包詳解GolangContext
- 深入理解golang:ContextGolangContext
- Golang —— goroutine(協程)和channel(管道)Golang
- Golang 獲取 goroutine id 完全指南Golang
- golang Context應用舉例GolangContext
- 深入理解 Golang 之 contextGolangContext
- Golang 的 goroutine 是如何實現的?Golang
- Golang 入門 : 等待 goroutine 完成任務Golang
- 「Golang成長之路」併發之GoroutineGolang
- 第 12 期 golang 中 goroutine 的排程Golang
- Golang併發程式設計——goroutine、channel、syncGolang程式設計
- 說說Golang goroutine併發那些事兒Golang
- Golang context (上下文)是什麼GolangContext
- golang 利用 WaitGroup 控制多個 goroutine 同時完成GolangAI
- Golang語言並行設計的核心goroutineGolang並行
- Go--關於 goroutine、channelGo
- golang multiple-value xxx in single-value contextGolangContext
- 2020-11-30-golang併發模式contextGolang模式Context
- Golang-goroutine02(MPG模式+設定CPU數目)Golang模式
- golang pprof 監控系列(4) —— goroutine thread 統計原理Golangthread
- React狀態管理之ContextReactContext
- Golang協程無法固定goroutine的最大數目解決Golang
- Golang語言goroutine協程併發安全及鎖機制Golang
- Goravel ORM 新增模型關聯,用 Golang 寫關聯也可以跟 Laravel 一樣簡單ORM模型GolangLaravel
- golang從context原始碼領悟介面的設計GolangContext原始碼
- Golang 高效實踐之併發實踐context篇GolangContext
- 伺服器開發利器 golang context 用法詳解伺服器GolangContext
- 《Lua-in-ConTeXt》07:時間管理Context
- 使用 Go Channel 及 Goroutine 時機Go
- 標識使用者 使用者關聯 IDM 全域使用者關聯
- Golang原始碼學習:排程邏輯(二)main goroutine的建立Golang原始碼AI
- Golang入門-Golang包管理Golang
- 關於webpack的require.contextWebUIContext
- 關於使用 Vue 實現 Context-Menu 的思考與總結VueContext