golang context接口類型方法介紹
摘要
在很多的 Go 開源框架里,我們經(jīng)常能看到 context 的身影,它的使用場(chǎng)景有很多,像超時(shí)通知,取消通知都用到了 context。今天我們就來好好的認(rèn)識(shí)一下它,看看 context 的相關(guān)知識(shí)和底層原理。
context 介紹
context 從它的字面量就可以看出來,是用來傳遞信息的。當(dāng)然,這種傳遞并不僅僅是將數(shù)據(jù)塞給被調(diào)用者,它還能進(jìn)行鏈?zhǔn)降膫鬟f,通過保存父子 context 關(guān)系,不斷的迭代遍歷來獲取數(shù)據(jù)。
除此之外,context 還能進(jìn)行鏈?zhǔn)降膫鞑?channel 信號(hào)。
我們知道 channel 是用來做 goroutine 通信使用的。這就使得 goroutine 之間能夠進(jìn)行鏈?zhǔn)降男盘?hào)通知了,進(jìn)而達(dá)到自上而下的通知效果。
例如通知所有跟 context 有血緣關(guān)系的 goroutine 進(jìn)行取消動(dòng)作。
Context 接口
在 Go 里并沒有直接為我們提供一個(gè)統(tǒng)一的 context 對(duì)象,而是設(shè)計(jì)了一個(gè)接口類型的 Context。然后在這些接口上來實(shí)現(xiàn)了幾種具體類型的 context。
這樣的好處就是我們只要根據(jù)開放出來的接口定義,也能夠?qū)崿F(xiàn)屬于自己的 context,進(jìn)而跟官方的 context 一起配合使用。
在分析官方的幾種 context 之前,我們先來看看 context 要求實(shí)現(xiàn)的幾個(gè)接口:
- Deadline() (deadline time.Time, ok bool)
- Done() <-chan struct{}
- Err() error
- Value(key interface{}) interface{}
其中:
Deadline()
表示如果有截止時(shí)間的話,得返回對(duì)應(yīng) deadline 時(shí)間;如果沒有,則 ok 的值為 false。
Done()
表示關(guān)于 channel 的數(shù)據(jù)通信,而且它的數(shù)據(jù)類型是 struct{},一個(gè)空結(jié)構(gòu)體,因此在 Go 里都是直接通過 close channel 來進(jìn)行通知的,不會(huì)涉及具體數(shù)據(jù)傳輸。
Err()
返回的是一個(gè)錯(cuò)誤 error,如果上面的 Done() 的 channel 沒被 close,則 error 為 nil;如果 channel 已被 close,則 error 將會(huì)返回 close 的原因,比如超時(shí)或手動(dòng)取消。
Value()
則是用來存儲(chǔ)具體數(shù)據(jù)的方法。
Context 類型
簡單的看過 Context 接口之后,我們來看看官方的 context 類型。主要有四種,分別是 emptyCtx
,cancelCtx
,timerCtx
,valueCtx
:
- emptyCtx:空的 context,實(shí)現(xiàn)了上面的 4 個(gè)接口,但都是直接 return 默認(rèn)值,沒有具體功能代碼。
- cancelCtx:用來取消通知用的 context
- timerCtx:用來超時(shí)通知用的 context
- valueCtx:用來傳值的 context
其中:
emptyCtx 表示什么都沒有的 context,一般用作最初始的 context,作為父 context 使用。像我們常見的 context.Background()
返回的就是 emptyCtx。
其他類型的創(chuàng)建方法如下:
- WithCancel 方法創(chuàng)建的是 cancelCtx 類型的 context。
- WithDeadline 方法創(chuàng)建的是 timerCtx 類型的 context。
- WithValue 方法創(chuàng)建的是 valueCtx 類型的 context。
上面三個(gè)方法在創(chuàng)建的時(shí)候都會(huì)要求傳 parent context 進(jìn)來,以此達(dá)到鏈?zhǔn)絺鬟f信息的目的。
Context 源碼
context 的源碼在 src/context/context.go 里,相信大家仔細(xì)研究,也能看到上面介紹的幾個(gè) context 對(duì)象。這邊簡單解釋下 cancelCtx
、timerCtx
、valueCtx
的核心流程。
1)cancelCtx 、timerCtx(用來通知用的 context)
cancelCtx 、timerCtx 在創(chuàng)建的時(shí)候都會(huì)調(diào)用 propagateCancel
方法,將當(dāng)前的 context 掛在 父 context 下。
接著在 Done() 方法里返回了對(duì)應(yīng)的 channel,讓調(diào)用者能夠監(jiān)聽 channel 信號(hào)。
當(dāng)要執(zhí)行取消動(dòng)作時(shí),會(huì)通過 cancel 方法關(guān)閉 channel,來達(dá)到通知 goroutine 的目的。
在 channel 關(guān)閉的同時(shí)也會(huì)對(duì)子 context 調(diào)用 cancel 方法,直到?jīng)]有子 context。
cancelCtx 和 timerCtxt 不同之處就在于 cancelCtx 是手動(dòng)調(diào)用 cancel 方法來觸發(fā)取消通知;
而 timerCtxt 則通過 AfterFunc 超時(shí)時(shí)間來自動(dòng)觸發(fā) cancel 方法。
2)valueCtx(用來傳值的 context)
valueCtx 通過 key-value 形式來存儲(chǔ)數(shù)據(jù),當(dāng)找不到 key 時(shí),就會(huì)到 父 context 里查找,直到?jīng)]有父 context:
func (c *valueCtx) Value(key interface{}) interface{} { if c.key == key { return c.val } return c.Context.Value(key) // 到父 context 里查找 }
context 注意事項(xiàng)
最后我們來看看在使用 context 時(shí)的幾個(gè)注意事項(xiàng):
- context 的 Done() 方法往往需要配合 select {} 使用,以監(jiān)聽退出。
- 盡量通過函數(shù)參數(shù)來暴露 context,不要在自定義結(jié)構(gòu)體里包含它。
- WithValue 類型的 context 應(yīng)該盡量存儲(chǔ)一些全局的 data,而不要存儲(chǔ)一些可有可無的局部 data。
- context 是并發(fā)安全的。
- 一旦 context 執(zhí)行取消動(dòng)作,所有派生的 context 都會(huì)觸發(fā)取消。
以上就是golang context接口類型方法介紹的詳細(xì)內(nèi)容,更多關(guān)于golang context接口類型的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Go語言使用buffer讀取文件的實(shí)現(xiàn)示例
本文主要介紹了Go語言使用buffer讀取文件的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04Go實(shí)現(xiàn)SSE消息推送的項(xiàng)目實(shí)戰(zhàn)
本文主要介紹了Go實(shí)現(xiàn)SSE消息推送的項(xiàng)目實(shí)戰(zhàn),結(jié)合JavaScript前端集成,構(gòu)建實(shí)時(shí)數(shù)據(jù)推送系統(tǒng),文中通過示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2025-05-05