context.context 是 go 語言中獨特的設計,在其他程式語言中我們很少見到類似的概念。上下文 context.context 是用來設定截止日期、同步訊號,傳遞請求相關值的結構體。上下文與 goroutine 有比較密切的關係。
context.context 是 go 語言在 1.7 版本中引入標準庫的介面,該介面定義了四個需要實現的方法,其中包括:
deadline — 返回 context.context 被取消的時間,也就是完成工作的截止日期;
done — 返回乙個 channel,這個 channel 會在當前工作完成或者上下文被取消之後關閉,多次呼叫 done 方法會返回同乙個 channel;
err — 返回 context.context 結束的原因,它只會在 done 返回的 channel 被關閉時才會返回非空的值;
如果 context.context 被取消,會返回 canceled 錯誤;
如果 context.context 超時,會返回 deadlineexceeded 錯誤;
value — 從 context.context 中獲取鍵對應的值,對於同乙個上下文來說,多次呼叫 value 並傳入相同的 key 會返回相同的結果,該方法可以用來傳遞請求特定的資料;
我們可以通過乙個**片段了解 context.context 是如何對訊號進行同步的。在這段**中,我們建立了乙個過期時間為 1s 的上下文,並向上下文傳入 handle 函式,該方法會使用 500ms 的時間處理傳入的『請求』:
因為過期時間大於處理時間,所以我們有足夠的時間處理該『請求』,執行上述**會列印出如下所示的內容:
handle 函式沒有進入超時的 select 分支,但是 main 函式的 select 卻會等待 context.context 的超時並列印出 main context deadline exceeded。
如果我們將處理『請求』時間增加至 1500ms,整個程式都會因為上下文的過期而被中止。
相信這兩個例子能夠幫助大家理解 context.context 的使用方法和設計原理:
多個 goroutine 同時訂閱 ctx.done() 管道中的訊息,一旦接收到取消訊號就立刻停止當前正在執行的工作。
函式能夠從 context.context 中衍生出乙個新的子上下文並返回用於取消該上下文的函式(cancelfunc)。
一旦我們執行返回的取消函式,當前上下文以及它的子上下文都會被取消,所有的 goroutine 都會同步收到這一取消訊號。
函式將傳入的上下文包裝成私有結構體 context.cancelctx
context.propagatecancel 會構建父子上下文之間的關聯,當父上下文被取消時,子上下文也會被取消
當 parent.done() == nil,也就是 parent 不會觸發取消事件時,當前函式會直接返回;
當 child 的繼承鏈包含可以取消的上下文時,會判斷 parent 是否已經觸發了取消訊號; 如果已經被取消,child會立刻被取消
如果沒有被取消,child 會被加入 parent 的 children 列表中,等待 parent 釋放取消訊號;
在預設情況下執行乙個新的 goroutine 同時監聽 parent.done() 和 child.done() 兩個 channel 在 parent.done() 關閉時呼叫 child.cancel 取消子上下文
作用是在 parent 和 child 之間同步取消和結束的訊號,保證在 parent 被取消時,child 也會收到對應的訊號,不會發生狀態不一致的問題。
context.cancelctx 實現的幾個介面方法也沒有太多值得分析的地方,該結構體最重要的方法是 cancel,這個方法會關閉上下文中的 channel 並向所有的子上下文同步取消訊號:
除了 context.withcancel 之外,context 包中的另外兩個函式context.withdeadline和context.withtimeout也都能建立可以被取消的計時器上下文 context.timerctx:
方法在建立 context.timerctx 的過程中,判斷了父上下文的截止日期與當前日期,並通過 time.afterfunc 建立定時器,當時間超過了截止日期後會呼叫 context.timerctx.cancel 方法同步取消訊號。
context.timerctx 結構體內部不僅通過嵌入了context.cancelctx 結構體繼承了相關的變數和方法,還通過持有的定時器 timer 和截止時間 deadline 實現了定時取消這一功能:
方法不僅呼叫了 context.cancelctx.cancel,還會停止持有的定時器減少不必要的資源浪費。
golang context強制提前退出
golang中context包實現提前退出 以前不知道怎麼寫的,一直無法退出,還以為程式就是無法提前退出。下面的程式,request休眠100s,然後在另外乙個goroutine中,3s後退出所有context import context log sync time func request va...
Golang Context的常規操作
golang context的常規操作 context是go的併發程式設計的常用模式,可以通過context來處理超時,取消任務等一系列操作 func main childctx,i time.after time.second 2 2秒後開始關閉 cancel 關掉paraentcontext,會...
伺服器開發利器golangcontext用法詳解
伺服器開發利器golangcontext用法詳解。在go伺服器中,對於每個請求的request都是在單獨的goroutine中進行的,處理乙個request也可能設計多個goroutine之間的互動,使用context可以使開發者方便的在這些goroutine裡傳遞request相關的資料 取消go...