go context學習

    • 1.Context接口
    • 2.emptyCtx
    • 3.Deadline()方法
    • 4.Done()方法
    • 5.Err方法
    • 6.Value方法()
    • 7.contex應用場景
    • 8.其他context方法

1.Context接口

Context接口只有四個方法,以下是context源碼。

type Context interface {Deadline() (deadline time.Time, ok bool)Done() <-chan struct{}Err() errorValue(key any) any
}

2.emptyCtx

context接口源碼中有兩個對外的實現,context.Background()和context.TODO(),都返回一個emptyCtx。

Background()和TODO()可以看作是emptyCtx的別名,用法如下:

  • Background(),當我們自己創建一個context,可以用context.Background();
  • TODO(),當我們調用一個方法,方法有個參數是context,我們又沒有context可以傳,就可以傳context.TODO()。
func Background() Context {return backgroundCtx{}
}
func TODO() Context {return todoCtx{}
}
type backgroundCtx struct{ emptyCtx }
type todoCtx struct{ emptyCtx }type emptyCtx struct{}
func (emptyCtx) Deadline() (deadline time.Time, ok bool) {return
}
func (emptyCtx) Done() <-chan struct{} {return nil
}
func (emptyCtx) Err() error {return nil
}
func (emptyCtx) Value(key any) any {return nil
}

3.Deadline()方法

Deadline() (deadline time.Time, ok bool)

返回這個context的deadline(結束時間)和ok,如果context設置了deadline,ok=ture,反之ok=false
如下可以看到,context如果沒有設置deadline,則默認時間是“0001-01-01 00:00:00 +0000 UTC”

func TestContextDeadline(t *testing.T) {ctx := context.Background()deadline, ok := ctx.Deadline()fmt.Println(deadline)     //輸出,0001-01-01 00:00:00 +0000 UTCfmt.Print(ok)  // 輸出,false
}

下面這是設置了時間的,可以看到dealine是當前時間加10秒,

func TestContextDeadline(t *testing.T) {fmt.Println(time.Now())ctx, _ := context.WithDeadline(context.Background(), time.Now().Add(10*time.Second))deadline, ok := ctx.Deadline()fmt.Println(deadline)fmt.Println(ok)
}
輸出:
2025-03-09 15:58:20.2027155 +0800 CST m=+0.001014101
2025-03-09 15:58:30.2080898 +0800 CST m=+10.006388401
true

如里對一個子contex設置的deadline時間比已有的contex大(就是比父context大),則不會生效

func TestContextDeadline2(t *testing.T) {fmt.Println(time.Now())ctx, _ := context.WithDeadline(context.Background(), time.Now().Add(10*time.Second))fmt.Println(ctx.Deadline())ctx2, _ := context.WithDeadline(ctx, time.Now().Add(15*time.Second))fmt.Println(ctx2.Deadline())
}
輸出:
2025-03-09 18:11:08.6194041 +0800 CST m=+0.001034701
2025-03-09 18:11:18.6251276 +0800 CST m=+10.006758201 true
2025-03-09 18:11:18.6251276 +0800 CST m=+10.006758201 true

ctx2的dealine并沒有加15秒,而是和父deadline一樣。
如果子deadline比父小,子deadline就會生效,并且父deadline不受影響。如下:

func TestContextDeadline2(t *testing.T) {fmt.Println(time.Now())ctx, _ := context.WithDeadline(context.Background(), time.Now().Add(10*time.Second))fmt.Println(ctx.Deadline())ctx2, _ := context.WithDeadline(ctx, time.Now().Add(5*time.Second))fmt.Println(ctx2.Deadline())fmt.Println(ctx.Deadline())
}
輸出:
2025-03-09 18:16:08.5541102 +0800 CST m=+0.003605801
2025-03-09 18:16:18.5612081 +0800 CST m=+10.010703701 true
2025-03-09 18:16:13.5612081 +0800 CST m=+5.010703701 true
2025-03-09 18:16:18.5612081 +0800 CST m=+10.010703701 true

4.Done()方法

Done() <-chan struct{}

Done()返回一個chan,當調用<-ctx.Done(),會一直阻塞,如果ctx的deadline時間到了,才能從chan返回

func TestContextDone(t *testing.T) {fmt.Println(time.Now())ctx, _ := context.WithDeadline(context.Background(), time.Now().Add(10*time.Second))deadline, ok := ctx.Deadline()fmt.Println(deadline)fmt.Println(ok)<-ctx.Done()   //Done()會一直阻塞等到deadline時間到了才結束fmt.Println(time.Now())    //當前時間加了10秒,因為<-ctx.Done() 阻塞了10秒
}
輸出:
2025-03-09 16:02:27.898926 +0800 CST m=+0.001548101
2025-03-09 16:02:37.9048716 +0800 CST m=+10.007493701
true
2025-03-09 16:02:37.9052627 +0800 CST m=+10.007884801

注意context.WithDeadline()方法還返回一個cancel

func TestContextDeadline(t *testing.T) {fmt.Println(time.Now())ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(10*time.Second))deadline, ok := ctx.Deadline()fmt.Println(deadline)fmt.Println(ok)cancel()    //cancel會讓context立刻結束,<-ctx.Done() ///Done()不會阻塞fmt.Println(time.Now())
}
輸出:
2025-03-09 17:25:36.815137 +0800 CST m=+0.001292801
2025-03-09 17:25:46.8209512 +0800 CST m=+10.007107001
true
2025-03-09 17:25:36.8209512 +0800 CST m=+0.007107001

如果ctx沒有設置deadline,ctx.Done()返回nil

func TestContextDone(t *testing.T) {ctx := context.Background()fmt.Println(ctx.Done())   //輸出nil
}

5.Err方法

Err() error

返回一個錯誤,有兩種錯誤
1.deadline時間到了
2.ctx被cancel了

以下是deadline時間到了的示例:

  • ctx設置10秒后結束 ,第一次調用ctx.Err(),輸出nill(因為還沒到10秒,ctx還沒結束)
  • 等到11秒后,ctx.Err()輸出了結束原因context deadline exceeded(deadline到時間結束)。

如果ctx結束了,調用ctx.Err()返回的結果一樣,下面調用了三次,結果一樣。

func TestContextErr(t *testing.T) {fmt.Println(time.Now())ctx, _ := context.WithDeadline(context.Background(), time.Now().Add(10*time.Second))fmt.Println(ctx.Err())time.Sleep(11 * time.Second)fmt.Println(time.Now())fmt.Println(ctx.Err())fmt.Println(ctx.Err())fmt.Println(ctx.Err())
}
輸出:
2025-03-09 16:17:04.7489444 +0800 CST m=+0.001009401
<nil>
2025-03-09 16:17:15.7551472 +0800 CST m=+11.007212201
context deadline exceeded
context deadline exceeded
context deadline exceeded

以下是cancel示例

func TestContextDeadline(t *testing.T) {fmt.Println(time.Now())ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(10*time.Second))deadline, ok := ctx.Deadline()fmt.Println(deadline)fmt.Println(ok)cancel()      //調用了cancel()<-ctx.Done() fmt.Println(time.Now())fmt.Println(ctx.Err())
}
輸出:
2025-03-09 17:54:11.8989047 +0800 CST m=+0.001138201
2025-03-09 17:54:21.9048333 +0800 CST m=+10.007066801
true
2025-03-09 17:54:11.9048333 +0800 CST m=+0.007066801
context canceled

6.Value方法()

Value(key any) any

就是往context存了key/value形式的數據,然后通過Value()方法取出這個值。

func TestContextValue(t *testing.T) {ctx := context.WithValue(context.Background(), "name", "daniel")fmt.Println(ctx.Value("name"))     //輸出daniel
}

7.contex應用場景

context是多線程安全的,常用于并發控制技術,在不同的goroutine之間同步請求特定的數據、取消信號以及處理請求的dealine(截止日期)。
通知其他goroutine結束
如下所示,設置findUser()方法只能查找用戶10秒鐘,10秒后強制結束這個goroutine。

func findUser(ctx context.Context, id int) {//輸出ctx結束時間fmt.Println(ctx.Deadline())for {//模擬根據id查找用戶time.Sleep(2 * time.Second)select {case <-ctx.Done():fmt.Println("ctx被取消,查找結束")fmt.Println(ctx.Err())fmt.Println(time.Now())returndefault:fmt.Println("正在查找中...")}}
}func TestContext(t *testing.T) {fmt.Println(time.Now())ctx, _ := context.WithDeadline(context.Background(), time.Now().Add(10*time.Second))go findUser(ctx, 100)time.Sleep(20 * time.Second)
}
輸出:
2025-03-09 16:46:05.7818671 +0800 CST m=+0.000000001
2025-03-09 16:46:15.7892368 +0800 CST m=+10.007369701 true
正在查找中...
正在查找中...
正在查找中...
正在查找中...
ctx被取消,查找結束
context deadline exceeded
2025-03-09 16:46:15.7919931 +0800 CST m=+10.010126001

8.其他context方法

cotext還有很多其他方法,相當于返回context的一個特定實現(context內部的實現),各有不同的功能。
在這里插入圖片描述
ctx, _ := context.WithDeadline(context.Background(), time.Now().Add(10*time.Second))
比如上面這個會返回一個帶deadline方法,其實是返回一個timerCtx,里面記下了deadline,
可以看到這些方法里面都有c.m.lock()方法,所以context是多線程安全的。
context源碼也比較簡單,有興趣自行看看源碼。
在這里插入圖片描述
timerCtx開頭是小寫的,也就是context內部的實現
在這里插入圖片描述
context.WithDeadlineCause()也可以自定義一個cause

func TestContextDeadlineCause(t *testing.T) {ctx, _ := context.WithDeadlineCause(context.Background(),time.Now().Add(10*time.Second), errors.New("my error"))fmt.Println(context.Cause(ctx))time.Sleep(11 * time.Second)  //context.Cause(ctx)先輸出nill,等結事時間到了才輸出真正的causefmt.Println(context.Cause(ctx))
}
輸出
<nil>
my error

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/897583.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/897583.shtml
英文地址,請注明出處:http://en.pswp.cn/news/897583.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

在VMware Workstation Pro上輕松部署CentOS7 Linux虛擬機

首先我們需要下載VM虛擬機和Centos7的鏡像 下載并安裝VMware Workstation Pro 訪問VMware Workstation Pro官網下載 https://www.vmware.com/ 第二步&#xff1a;下載centos7鏡像 訪問centos官網下載 https://www.centos.org/ 開始部署Centos7 點擊創建新的虛擬機 這里是Cen…

Jsoup 解析商品信息時需要注意哪些細節?

在使用Jsoup解析商品信息時&#xff0c;需要注意以下細節和最佳實踐&#xff0c;以確保爬蟲的穩定性和數據的準確性&#xff1a; 1. 檢查HTML文檔的合法性 在解析之前&#xff0c;需要確認所解析的文檔是否是一份合法正確的HTML文檔。如果HTML結構不完整或存在錯誤&#xff0…

Android AudioFlinger(五)—— 揭開AudioMixer面紗

前言&#xff1a; 在 Android 音頻系統中&#xff0c;AudioMixer 是音頻框架中一個關鍵的組件&#xff0c;用于處理多路音頻流的混音操作。它主要存在于音頻回放路徑中&#xff0c;是 AudioFlinger 服務的一部分。 上一節我們講threadloop的時候&#xff0c;提到了一個函數pr…

go的”ambiguous import in multiple modules”

執行“go mod tidy”報如下錯誤&#xff1a; go mod tidy -compat1.17 go: finding module for package github.com/gomooon/goredis go: found github.com/gomooon/goredis in github.com/gomooon/goredis v0.3.5 go: github.com/gomooon/core importsgithub.com/gomooon/gor…

從0開始的操作系統手搓教程27:下一步,實現我們的用戶進程

目錄 第一步&#xff1a;添加用戶進程虛擬空間 準備沖向我們的特權級3&#xff08;用戶特權級&#xff09; 討論下我們創建用戶線程的基本步驟 更加詳細的分析代碼 用戶進程的視圖 說一說BSS段 繼續看process.c中的函數 添加用戶線程激活 現在&#xff0c;我們做好了TSS…

Java線程池深度解析,從源碼到面試熱點

Java線程池深度解析&#xff0c;從源碼到面試熱點 一、線程池的核心價值與設計哲學 在開始討論多線程編程之前&#xff0c;可以先思考一個問題&#xff1f;多線程編程的原理是什么&#xff1f; 我們知道&#xff0c;現在的CUP是多核CPU&#xff0c;假設你的機器是4核的&#x…

大數據技術在土地利用規劃中的應用分析

大數據技術在土地利用規劃中的應用分析 一、引言 土地利用規劃是對一定區域內的土地開發、利用、整治和保護所作出的統籌安排與戰略部署,對于實現土地資源的優化配置、保障社會經濟的可持續發展具有關鍵意義。在當今數字化時代,大數據技術憑借其海量數據處理、高效信息挖掘等…

Node 使用 SSE 結合redis 推送數據(echarts 圖表實時更新)

1、實時通信有哪些實現方式&#xff1f; 特性輪詢&#xff08;Polling&#xff09;WebSocketSSE (Server-Sent Events)通信方向單向&#xff08;客戶端 → 服務端&#xff09;雙向&#xff08;客戶端 ? 服務端&#xff09;單向&#xff08;服務端 → 客戶端&#xff09;連接方…

Android Native 之 文件系統掛載

一、文件系統掛載流程概述 二、文件系統掛載流程細節 1、Init啟動階段 眾所周知&#xff0c;init進程為android系統的第一個進程&#xff0c;也是native世界的開端&#xff0c;要想讓整個android世界能夠穩定的運行&#xff0c;文件系統的創建和初始化是必不可少的&#xff…

Redis--Set類型

目錄 一、引言 二、介紹 三、命令 1.sadd,smembers,sismember 2.spop&#xff0c;srandmember 3.smove&#xff0c;srem 4.sinter&#xff0c;sinterstore 5.sunion,sunionstore,sdiff,sdiffstore 四、內部編碼 1.intset 2.hashtable 五、應用場景 1.使用Set保存用…

for...of的用法與介紹

一、定義 for...of 是 ES6&#xff08;ECMAScript 2015&#xff09;引入的一種用于 遍歷可迭代對象&#xff08;Iterable&#xff09;的循環語句 二、語法 for (const item of iterable) {// 代碼塊 }參數&#xff1a; iterable&#xff1a;一個可迭代對象&#xff08;如數組…

Faster R-CNN原理詳解以及Pytorch實現模型訓練與推理

《------往期經典推薦------》 一、AI應用軟件開發實戰專欄【鏈接】 項目名稱項目名稱1.【人臉識別與管理系統開發】2.【車牌識別與自動收費管理系統開發】3.【手勢識別系統開發】4.【人臉面部活體檢測系統開發】5.【圖片風格快速遷移軟件開發】6.【人臉表表情識別系統】7.【…

使用dockerfile創建鏡像

1.什么是Dockerfile Dockerfile 是一個用于指導 Docker 鏡像構建過程的腳本文件。它通過一系列指令來詳細描述了構建鏡像所需的步驟和配置細節。利用 Dockerfile&#xff0c;我們可以精確地設定容器的運行環境&#xff0c;安裝必要的軟件&#xff0c;復制項目文件&#xff0c;…

在CentOS系統上安裝Conda的詳細指南

前言 Conda 是一個開源的包管理系統和環境管理系統&#xff0c;廣泛應用于數據科學和機器學習領域。本文將詳細介紹如何在 CentOS 系統上安裝 Conda&#xff0c;幫助您快速搭建開發環境。 準備工作 在開始安裝之前&#xff0c;請確保您的 CentOS 系統已經滿足以下條件&#x…

大腦宏觀結構中的富集俱樂部:圖論分析視角

摘要 大腦是一個高度復雜的網絡。越來越多的證據支持大腦網絡中一組重要腦區的關鍵作用&#xff0c;這些腦區通常被稱為大腦的“核心”或“樞紐”區域。這些區域不僅能量消耗較高&#xff0c;而且在神經信息傳遞方面的效率也極高&#xff0c;因此被稱為“富集俱樂部”。富集俱樂…

Redis7——進階篇(五)

前言&#xff1a;此篇文章系本人學習過程中記錄下來的筆記&#xff0c;里面難免會有不少欠缺的地方&#xff0c;誠心期待大家多多給予指教。 基礎篇&#xff1a; Redis&#xff08;一&#xff09;Redis&#xff08;二&#xff09;Redis&#xff08;三&#xff09;Redis&#x…

Reflect.get和target[key]有何不同?

主要區別在this指向不同&#xff0c;下面輸出張三還是李四?&#xff1a; const person{name:張三,get FullName(){return this.name;},};let personProxynew Proxy(person,{get(target,key){return Reflect.get(target,key)//或者return target[key]}});const p1{__proto__:pe…

rust語言match模式匹配涉及轉移所有權Error Case

struct S{data:String, }//注意&#xff1a;因為String默認是移動語義&#xff0c;從而決定結構體S也是移動語義&#xff0c;可采用(1)或(2)兩種方法解決編譯錯誤&#xff1b;關鍵思路&#xff1a;放棄獲取結構體S的字段data的所有權&#xff0c;改為借用。fn process(s_ref:&a…

光譜相機檢測肉類新鮮度的原理

光譜相機通過分析肉類樣本在特定波長范圍內的光譜反射特性&#xff0c;結合化學與生物指標的變化規律&#xff0c;實現對其新鮮度的無損檢測。其核心原理可概括為以下方面&#xff1a; 一、光譜特征與物質成分的關聯性 ?物質特異性吸收/反射? 不同化學成分&#xff08;如水分…

c#面試題整理9

1.遍歷xml文檔 2.解釋一下這段 String s new String("xyz"); 這段在C#平臺中&#xff0c;編譯失敗 3.說明一下抽象類 抽象類可以有構造函數 抽象類不能是靜態和密封的類&#xff0c;密封的類表示無法繼承&#xff0c;抽象類本身就不可實例化&#xff0c;加不好…