context
是控制並發的一個 package,之前在 Worker Pool 也有提到過另一個 WaitGroup
,那為什麼需要兩種,來了解一下
WaitGroup
當所有的 goroutine
都完成後,才算完成
實際場景
有個監控程式跑很多 gorountine
,當要停止時,就必須通知每個 gorountine
並等待所有都完成,才算完成,否則會造成記憶體洩漏
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
大部分的 gorountine
啟動後,就會一直跑,大部分情況是等待它自己結束,如果是不會結束的 gorountine
,就會一直跑下去,比較笨的方式就是,用一個變數去判斷是否要結束,但這樣就必須一直去檢查這個變數
因此可以改用 chan + select
來通知
chan + select
這方式很好的解決上述的問題,並且可以透過給予 chan
值來決定是否要停止,但還是有其他問題
- 如果有很多
goroutine
都需要控制結束怎麼辦? goroutine
又衍生了其它更多的goroutine怎麼?
即使定義很多 chan
也很難解決這個問題,因為 goroutine
的關係鏈就導致了這種場景非常複雜,因此就有另一個方式 context
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
context
上面提到的情境是多層級的 goroutine
,因此要控制就必須跟蹤 groutine
因此 golang 提供了 context
來控制,也就是 groutine
的上下文
Context 使用原則
- 不要把 Context 放在結構體中,要以參數的方式傳遞
- 以 Context 作為參數的函式方法,應該把 Context 作為第一個參數,放在第一位。
- 給一個函式方法傳遞 Context 的時候,不要傳遞 nil,如果不知道傳遞什麼,就使用
context.TODO
- Context 的 Value 相關方法應該傳遞必須的數據,不要什麼數據都使用這個傳遞
- Context 是執行緒安全的,可以放心的在多個 goroutine 中傳遞
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
|
context.Background()
回傳一個非 nil 的空 context,不會被取消也沒有值或時間,就是 context 的根節點context.WithCancel(parent)
建立一個可取消的子 context
當作參數來追蹤goroutine
,另外一個是cancle
用於取消這個子 context
ctx.Done
判斷是否要結束,透過cancel()
來取消
目前為止似乎跟 chan
沒什麼兩樣?接著試著控制多個 goroutine
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
|
可以看到,上面即使有多個 goroutine
依樣只要一個 cancel()
就全部都取消了
如果是用之前 chan
,變成只有一個 true
只能夠取消一個,就結束了,導致剩下的 memory 沒辦法釋放,或是一次放三個 true
去控制,但是當一多起來,就會變得很複雜
Context interface
1 2 3 4 5 6 7 8 9 |
|
Deadline()
是獲取設定的截止時間的意思deadline
截止時間,到了這個時間點,Context 會自動發起取消請求ok
如果是 false,表示沒有設定截止時間,如果需要取消的話,需要呼叫取消函式進行取消
Done
返回一個只讀的 chan
,類型為 struct{}- 如果可讀取,表示
parent context
已發起取消的請求(cancel
),收到信號時就會開始清理操作,然後退出 goroutine,釋放資源
- 如果可讀取,表示
Err
返回取消的錯誤原因,因為什麼 Context 被取消Value
獲取該 Context 上繫結的值,是一個鍵值對,所以要透過一個 Key 才可以獲取對應的值,這個值一般是執行緒安全的
Other
- WithCancel 主動取消
- WithDeadline 截止時間取消
- WithTimeout 超時取消
- WithValue 傳值
- 也可以不包上面的 With,直接使用
context.Background()
,可以看到上面的 With 最後回傳的也是context Context
Reference