日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
Go1.21速覽:Context可以設(shè)置取消原因和回調(diào)函數(shù)了,等的可太久了!

大家好,我是煎魚。

創(chuàng)新互聯(lián)是一家專注于成都網(wǎng)站制作、成都網(wǎng)站建設(shè)與策劃設(shè)計(jì),義縣網(wǎng)站建設(shè)哪家好?創(chuàng)新互聯(lián)做網(wǎng)站,專注于網(wǎng)站建設(shè)10年,網(wǎng)設(shè)計(jì)領(lǐng)域的專業(yè)建站公司;建站業(yè)務(wù)涵蓋:義縣等地區(qū)。義縣做網(wǎng)站價(jià)格咨詢:028-86922220

在 Go 中有一個(gè)很經(jīng)典的設(shè)計(jì):context,這是許多同學(xué)初學(xué)時(shí)必學(xué)的標(biāo)準(zhǔn)庫(kù)。涉及到上下文傳遞、超時(shí)控制等必要項(xiàng)。

甚至在函數(shù)體中的第一個(gè)參數(shù)大多是傳 context。寫第三方庫(kù)也必須兼容 context 設(shè)置,否則會(huì)經(jīng)常有人提需求讓你支持。

我覺(jué)得這次的新特性更新雖不復(fù)雜,但作用挺大。建議大家學(xué)習(xí)!

Context Demo

以下是一個(gè)快速 Demo:

package main

import (
 "context"
 "fmt"
 "time"
)

const shortDuration = 1 * time.Millisecond

func main() {
 ctx, cancel := context.WithTimeout(context.Background(), shortDuration)
 defer cancel()

 select {
 case <-time.After(1 * time.Second):
  fmt.Println("overslept")
 case <-ctx.Done():
  fmt.Println(ctx.Err())
 }

}

運(yùn)行結(jié)果:

context deadline exceeded

一切都看起來(lái)沒(méi)什么問(wèn)題。

麻煩點(diǎn)

但在實(shí)際寫業(yè)務(wù)代碼和排查問(wèn)題時(shí),你就會(huì)發(fā)現(xiàn)一個(gè)麻煩的事。在出現(xiàn)上下文超時(shí)或到達(dá)所設(shè)置的截止時(shí)間時(shí),ctx.Err 方法可以獲得 context deadline exceeded 的錯(cuò)誤信息。

但這是遠(yuǎn)遠(yuǎn)不夠的,你只知道是因?yàn)檎T發(fā)了超時(shí)。但不知道是哪里導(dǎo)致的,還得再去根據(jù)訪問(wèn)的邏輯,再走一遍腦洞,再進(jìn)行排查。又或是根據(jù)代碼堆棧,再去設(shè)想,最后復(fù)現(xiàn)成功。

又或是查不到。因?yàn)檫@種一般是偶現(xiàn),很有可能就留給下一代的繼承者了~

又更有業(yè)務(wù)訴求,希望在出現(xiàn)上下文的異常場(chǎng)景時(shí),可以及時(shí)執(zhí)行回調(diào)方法。然而這沒(méi)有太便捷的實(shí)現(xiàn)方式。

Go1.21 增強(qiáng) Context

增加 WithXXXCause

在即將發(fā)布的 Go1.21,針對(duì) Context 的錯(cuò)誤處理終于有了一點(diǎn)點(diǎn)的增強(qiáng),來(lái)填補(bǔ)這個(gè)地方的信息,允許添加自定義的錯(cuò)誤類型和信息。

新增的 Context API 如下:

// WithDeadlineCause behaves like WithDeadline but also sets the cause of the
// returned Context when the deadline is exceeded. The returned CancelFunc does
// not set the cause.
func WithDeadlineCause(parent Context, d time.Time, cause error) (Context, CancelFunc)

// WithTimeoutCause behaves like WithTimeout but also sets the cause of the
// returned Context when the timout expires. The returned CancelFunc does
// not set the cause.
func WithTimeoutCause(parent Context, timeout time.Duration, cause error) (Context, CancelFunc)

與原先的 WithDeadline 和 WithTimeout 作用基本一致,唯一區(qū)別就是在形參上增加了 cause error,允許傳入錯(cuò)誤類型。

WithTimeoutCause

WithTimeoutCause 的使用示例:

tooSlow := fmt.Errorf("too slow!")
ctx, cancel := context.WithTimeoutCause(context.Background(), 1*time.Second, tooSlow)
time.Sleep(2*time.Second)
cancel()

像上述程序,執(zhí)行 ctx.Err 方法時(shí)得到的結(jié)果是:context.DeadlineExceeded,這是既有的。

此時(shí),我們?cè)俳Y(jié)合在 Go1.20 版本加入的 context.Cause 方法:

func Cause(c Context) error

就能得到對(duì)應(yīng)的錯(cuò)誤信息,上述的結(jié)果對(duì)應(yīng)的是 tooSlow 變量。

WithCancelCause

WithCancelCause 的使用示例,計(jì)時(shí)器先觸發(fā):

finishedEarly := fmt.Errorf("finished early")
tooSlow := fmt.Errorf("too slow!")
ctx, cancel := context.WithCancelCause(context.Background())
ctx, _ = context.WithTimeoutCause(ctx, 1*time.Second, tooSlow)
time.Sleep(2*time.Second) // timer fires, setting the cause
cancel(finishedEarly) // no effect as ctx has already been canceled

對(duì)應(yīng)的程序結(jié)果:

  • ctx.Err():context.DeadlineExceeded 類型。
  • context.Cause(ctx):tooSlow 類型。

先發(fā)生上下文取消的使用示例:

finishedEarly := fmt.Errorf("finished early")
tooSlow := fmt.Errorf("too slow!")
ctx, cancel := context.WithCancelCause(context.Background())
ctx, _ = context.WithTimeoutCause(ctx, 1*time.Second, tooSlow)
time.Sleep(500*time.Millisecond) // timer hasn't expired yet
cancel(finishedEarly) // cancels the timer and sets ctx.Err()

對(duì)應(yīng)的程序結(jié)果:

  • ctx.Err():context.Canceled 類型。
  • context.Cause(ctx):finishedEarly 類型。

增加 AfterFunc

同樣的,在 Go1.21 也對(duì) Context(上下文)被取消的動(dòng)作后增加了一些增強(qiáng)。平時(shí)當(dāng)上下文被取消時(shí),我們只能通過(guò)啟動(dòng) Goroutine 來(lái)監(jiān)視取消行為并做一系列操作。

但這未免繁瑣且增大了我們的編碼和運(yùn)行成本,因?yàn)槊看翁幚矶家?goroutine+select+channel 來(lái)一套組合拳,才能真正到寫自己業(yè)務(wù)代碼的地方。

為此新版本增加了注冊(cè)函數(shù)的功能,將會(huì)在上下文被取消時(shí)調(diào)用。函數(shù)簽名如下:

func AfterFunc(ctx Context, f func()) (stop func() bool)

在函數(shù)作用上,該函數(shù)會(huì)在 ctx 完成(取消或超時(shí))后調(diào)用所傳入的函數(shù) f。

在運(yùn)行機(jī)制上,它會(huì)自己在 goroutine 中調(diào)用 f。需要注意的是,即使 ctx 已經(jīng)完成,調(diào)用 AfterFunc 也不會(huì)等待 f 返回。

這也是可以套娃的,在 AfterFunc 里再套 AfterFunc。這里用不好也很容易 goroutine 泄露。

基于這個(gè)新函數(shù),可以看看以下兩個(gè)例子作為使用場(chǎng)景。

1、多 Context 合并取消的例子:

func WithFirstCancel(ctx1, ctx2 context.Context) (context.Context, context.CancelFunc) {
 ctx, cancel := context.WithCancel(ctx1)
 stopf := context.AfterFunc(ctx2, func() {
  cancel()
 })
 return ctx, func() {
  cancel()
  stopf()
 }
}

2、在取消上下文時(shí)停止等待 sync.Cond:

func Wait(ctx context.Context, cond *sync.Cond) error {
 stopf := context.AfterFunc(ctx, cond.Broadcast)
 defer stopf()
 cond.Wait()
 return ctx.Err()
}

基本滿足了各種上下文的復(fù)雜訴求了。

總結(jié)

Context 一直是大家使用的最頻繁的標(biāo)準(zhǔn)庫(kù)之一,他聯(lián)通了整個(gè) Go 里的工程體系。這次在 Go1.21 對(duì) Context 增加了 WithXXXCause 相關(guān)函數(shù)的錯(cuò)誤類型支持。對(duì)于我們?cè)?Go 工程實(shí)踐中的排查和定位,能夠有一些不錯(cuò)的助力。

另外 AfterFunc 函數(shù)的增加,看起來(lái)是個(gè)簡(jiǎn)單的功能。但是可以解決以往的一些合并取消上下文和串聯(lián)處理的復(fù)雜場(chǎng)景,是一個(gè)不錯(cuò)的擴(kuò)展功能。

苛刻些,美中不足的就是,Go 都已經(jīng)發(fā)布 10+ 年了,加的還是有些太晚了。同時(shí)針對(duì) Context 也需要有更體系的排查和定位側(cè)的補(bǔ)全了。


分享名稱:Go1.21速覽:Context可以設(shè)置取消原因和回調(diào)函數(shù)了,等的可太久了!
瀏覽地址:http://m.5511xx.com/article/dhoesie.html