自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Go1.21 速覽:Context 可以設置取消原因和回調(diào)函數(shù)了,等的可太久了!

開發(fā) 前端
Context 一直是大家使用的最頻繁的標準庫之一,他聯(lián)通了整個 Go 里的工程體系。這次在 Go1.21 對 Context 增加了 WithXXXCause 相關函數(shù)的錯誤類型支持。對于我們在 Go 工程實踐中的排查和定位,能夠有一些不錯的助力。

大家好,我是煎魚。

在 Go 中有一個很經(jīng)典的設計:context,這是許多同學初學時必學的標準庫。涉及到上下文傳遞、超時控制等必要項。

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

我覺得這次的新特性更新雖不復雜,但作用挺大。建議大家學習!

Context Demo

以下是一個快速 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())
 }

}

運行結果:

context deadline exceeded

一切都看起來沒什么問題。

麻煩點

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

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

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

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

Go1.21 增強 Context

增加 WithXXXCause

在即將發(fā)布的 Go1.21,針對 Context 的錯誤處理終于有了一點點的增強,來填補這個地方的信息,允許添加自定義的錯誤類型和信息。

新增的 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,允許傳入錯誤類型。

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 方法時得到的結果是:context.DeadlineExceeded,這是既有的。

此時,我們再結合在 Go1.20 版本加入的 context.Cause 方法:

func Cause(c Context) error

就能得到對應的錯誤信息,上述的結果對應的是 tooSlow 變量。

WithCancelCause

WithCancelCause 的使用示例,計時器先觸發(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

對應的程序結果:

  • 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()

對應的程序結果:

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

增加 AfterFunc

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

但這未免繁瑣且增大了我們的編碼和運行成本,因為每次處理都要 goroutine+select+channel 來一套組合拳,才能真正到寫自己業(yè)務代碼的地方。

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

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

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

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

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

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

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、在取消上下文時停止等待 sync.Cond:

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

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

總結

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

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

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

責任編輯:武曉燕 來源: 腦子進煎魚了
相關推薦

2023-06-07 10:32:57

內(nèi)置函數(shù)clear

2023-06-19 08:49:55

go文件管理

2023-05-05 08:51:18

Go語言泛型

2023-07-05 08:47:24

Go版本團隊

2018-04-09 14:26:06

Go語法實踐

2023-08-09 08:53:50

GoWASI語義

2012-02-01 10:33:59

Java

2025-01-14 11:01:38

2011-06-15 11:05:14

C語言回調(diào)函數(shù)

2023-08-02 08:46:02

Go版本號規(guī)則

2011-10-31 14:04:40

Windows XP

2023-04-18 08:10:10

2011-07-25 14:32:40

Cocoa 框架 函數(shù)

2022-04-12 08:30:52

回調(diào)函數(shù)代碼調(diào)試

2019-11-05 10:03:08

callback回調(diào)函數(shù)javascript

2011-05-20 17:59:06

回調(diào)函數(shù)

2022-04-18 08:34:29

回調(diào)函數(shù)命令解析

2021-01-14 07:52:24

JavaScript回調(diào)函數(shù)

2017-11-23 15:24:35

Python速覽實戰(zhàn)

2013-11-22 16:45:28

SASJMP11
點贊
收藏

51CTO技術棧公眾號