亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

GO語言Context的作用及各種使用方法

 更新時間:2024年01月15日 10:32:10   作者:過去日記  
golang的Context包是專門用來處理多個goroutine之間與請求域的數(shù)據(jù)、取消信號、截止時間等相關操作,下面這篇文章主要給大家介紹了關于GO語言Context的作用及各種使用方法的相關資料,需要的朋友可以參考下

Context

為什么需要Context

Go語言需要Context主要是為了在并發(fā)環(huán)境中有效地管理請求的上下文信息。Context提供了在函數(shù)之間傳遞取消信號、超時、截止時間等元數(shù)據(jù)的一種標準方式。

原因

  • 取消操作: 在并發(fā)環(huán)境中,當一個請求被取消或者超時時,需要有效地通知相關的協(xié)程停止正在進行的工作。使用Context可以通過傳遞取消信號來實現(xiàn)這一點。
  • 超時控制: 在一些場景下,限制操作執(zhí)行的時間是很重要的。Context提供了一個統(tǒng)一的方式來處理超時,確保在規(guī)定的時間內(nèi)完成操作,防止程序無限期地等待。
  • 傳遞上下文信息: Context可以用于傳遞請求的元數(shù)據(jù),例如請求的ID、用戶信息等。這在跨多個函數(shù)調(diào)用的情況下非常有用,避免了在函數(shù)參數(shù)中傳遞大量的上下文信息。
  • 協(xié)程之間的通信: Go語言中的協(xié)程(goroutine)是輕量級的線程,它們之間需要有效地通信。Context提供了一個標準的方式來傳遞信號和元數(shù)據(jù),以便協(xié)程之間協(xié)同工作。
  • 資源管理: 在一些場景下,需要確保在函數(shù)執(zhí)行完畢后釋放相關的資源,不管函數(shù)是正常執(zhí)行還是因為取消或超時而提前退出。Context可以幫助在正確的時機釋放資源。
  • 綜上所述,Context是Go語言中處理并發(fā)、超時和取消等問題的一種優(yōu)雅而一致的方式,使得代碼更加健壯、可維護,并且更容易在不同的并發(fā)場景中工作。

多任務超時例子

我們都知道在go語言并發(fā)編程中,我們可以采用select來監(jiān)聽協(xié)程的的通道控制協(xié)程,但是如下面的這種情況僅僅憑借select就顯得有些無能為力:

  • 支持多級嵌套,父任務停止后,子任務自動停止
  • 控制停止順序,先停EFG 再停BCD 最后停A

目標1還好說,目標2好像就沒那么靈活了,正式討論context如何解決這些問題前,我們先看下常規(guī)context的使用

Context結(jié)構(gòu)

context 包是 Go 語言中用于處理請求的上下文的標準庫之一。它提供了一種在函數(shù)之間傳遞取消信號、超時和截止時間的機制。

type Context interface {
	Deadline() (deadline time.Time, ok bool)
	Done() <-chan struct{}
	Err() error
	Value(key interface{}) interface{}
}
  • Deadline()返回一個完成工作的截止時間,表示上下文應該被取消的時間。如果 ok==false 表示沒有設置截止時間。

  • Done()返回一個 Channel,這個 Channel 會在當前工作完成時被關閉,表示上下文應該被取消。如果無法取消此上下文,則 Done 可能返回 nil。多次調(diào)用 Done 方法會返回同一個 Channel。

  • Err()返回 Context 結(jié)束的原因,它只會在 Done 方法對應的 Channel 關閉時返回非空值。如果 Context 被取消,會返回context.Canceled 錯誤;如果 Context 超時,會返回context.DeadlineExceeded錯誤。

  • Value()從 Context 中獲取鍵對應的值。如果未設置 key 對應的值則返回 nil。以相同 key 多次調(diào)用會返回相同的結(jié)果。

另外,context 包中提供了兩個創(chuàng)建默認上下文的函數(shù):

// TODO 返回一個非 nil 但空的上下文。
// 當不清楚要使用哪種上下文或無可用上下文尚應使用 context.TODO。
func TODO() Context

// Background 返回一個非 nil 但空的上下文。
// 它不會被 cancel,沒有值,也沒有截止時間。它通常由 main 函數(shù)、初始化和測試使用,并作為處理請求的頂級上下文。
func Background() Context

還有四個基于父級創(chuàng)建不同類型上下文的函數(shù):

// WithCancel 基于父級創(chuàng)建一個具有 Done channel 的 context
func WithCancel(parent Context) (Context, CancelFunc)

// WithDeadline 基于父級創(chuàng)建一個不晚于 d 結(jié)束的 context
func WithDeadline(parent Context, d time.Time) (Context, CancelFunc)

// WithTimeout 等同于 WithDeadline(parent, time.Now().Add(timeout))
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)

// WithValue 基于父級創(chuàng)建一個包含指定 key 和 value 的 context
func WithValue(parent Context, key, val interface{}) Context

在后面會詳細介紹這些不同類型 context 的用法。

Context各種使用方法

創(chuàng)建context

context包主要提供了兩種方式創(chuàng)建context:

  • context.Backgroud()
  • context.TODO()

這兩個函數(shù)其實只是互為別名,沒有差別,官方給的定義是:

  • context.Background 是上下文的默認值,所有其他的上下文都應該從它衍生(Derived)出來。
  • context.TODO 應該只在不確定應該使用哪種上下文時使用;
    所以在大多數(shù)情況下,我們都使用context.Background作為起始的上下文向下傳遞。

上面的兩種方式是創(chuàng)建根context,不具備任何功能,具體實踐還是要依靠context包提供的With系列函數(shù)來進行派生:

func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc)
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
func WithValue(parent Context, key, val interface{}) Context

valueCtx

valueCtx結(jié)構(gòu)體

type valueCtx struct {
    Context
    key, val interface{}
}

func (c *valueCtx) Value(key interface{}) interface{} {
    if c.key == key {
        return c.val
    }
    return c.Context.Value(key)
}

valueCtx利用一個Context類型的變量來表示父節(jié)點context,所以當前context繼承了父context的所有信息;valueCtx類型還攜帶一組鍵值對,也就是說這種context可以攜帶額外的信息。valueCtx實現(xiàn)了Value方法,用以在context鏈路上獲取key對應的值,如果當前context上不存在需要的key,會沿著context鏈向上尋找key對應的值,直到根節(jié)點。

WithValue

我們?nèi)粘T跇I(yè)務開發(fā)中都希望能有一個trace_id能串聯(lián)所有的日志,這就需要我們打印日志時能夠獲取到這個trace_id,在python中我們可以用gevent.local來傳遞,在java中我們可以用ThreadLocal來傳遞,在Go語言中我們就可以使用Context來傳遞,通過使用WithValue來創(chuàng)建一個攜帶trace_id的context,然后不斷透傳下去,打印日志時輸出即可,來看使用例子:

package main

import (
	"context"
	"fmt" // 我們需要使用fmt包中的Println()函數(shù)
	"strings"
	"time"

	"github.com/google/uuid"
)

const (
	KEY = "trace_id"
)

// 生成隨機ID
func NewRequestID() string {
	return strings.Replace(uuid.New().String(), "-", "", -1)
}
// 生成攜帶值的context
func NewContextWithTraceID() context.Context {
	ctx := context.WithValue(context.Background(), KEY, NewRequestID())
	return ctx
}
//打印數(shù)據(jù)
func PrintLog(ctx context.Context, message string) {
	fmt.Printf("%s|info|trace_id=%s|%s", time.Now().Format("2006-01-02 15:04:05"), GetContextValue(ctx, KEY), message)
}
// 獲取context中的值
func GetContextValue(ctx context.Context, k string) string {
	v, ok := ctx.Value(k).(string)
	if !ok {
		return ""
	}
	return v
}

func ProcessEnter(ctx context.Context) {
	PrintLog(ctx, "Golang夢工廠")
}

func main() {
	ProcessEnter(NewContextWithTraceID())
}

結(jié)果

2024-01-10 18:55:03|info|trace_id=c4eeb76d427449fda52a4775ccbc0509|Golang夢工廠

cancelCtx

cancelCtx結(jié)構(gòu)體

type cancelCtx struct {
    Context

    mu       sync.Mutex            // 同步鎖,保護下面的所有字段
    done     chan struct{}         //惰性創(chuàng)建,由第一次取消調(diào)用關閉
    children map[canceler]struct{} // 在第一次取消調(diào)用時,設置為 nil
    err      error                 // 在第一次取消調(diào)用時設置為 non-nil 
}

type canceler interface {
    cancel(removeFromParent bool, err error)
    Done() <-chan struct{}
}

跟valueCtx類似,cancelCtx中也有一個context變量作為父節(jié)點;變量done表示一個channel,用來表示傳遞關閉信號;children表示一個map,存儲了當前context節(jié)點下的子節(jié)點;err用于存儲錯誤信息表示任務結(jié)束的原因。

withCancel

日常業(yè)務開發(fā)中我們往往為了完成一個復雜的需求會開多個gouroutine去做一些事情,這就導致我們會在一次請求中開了多個goroutine確無法控制他們,這時我們就可以使用withCancel來衍生一個context傳遞到不同的goroutine中,當我想讓這些goroutine停止運行,就可以調(diào)用cancel來進行取消。

package main

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

func main() {
	ctx, cancel := context.WithCancel(context.Background())
	go Speak(ctx)
	time.Sleep(10 * time.Second)
	cancel()
	time.Sleep(1 * time.Second)
}

func Speak(ctx context.Context) {
	for range time.Tick(time.Second) {
		select {
		case <-ctx.Done():
			fmt.Println("我要閉嘴了")
			return
		default:
			fmt.Println("balabalabalabala")
		}
	}
}

timerCtx

timerCtx是一種基于cancelCtx的context類型,從字面上就能看出,這是一種可以定時取消的context。

type timerCtx struct {
    cancelCtx
    timer *time.Timer // Under cancelCtx.mu.

    deadline time.Time
}

func (c *timerCtx) Deadline() (deadline time.Time, ok bool) {
    return c.deadline, true
}

func (c *timerCtx) cancel(removeFromParent bool, err error) {
    //將內(nèi)部的cancelCtx取消
    c.cancelCtx.cancel(false, err)
    if removeFromParent {
        // Remove this timerCtx from its parent cancelCtx's children.
        removeChild(c.cancelCtx.Context, c)
    }
    c.mu.Lock()
    if c.timer != nil {
        取消計時器
        c.timer.Stop()
        c.timer = nil
    }
    c.mu.Unlock()
}

timerCtx內(nèi)部使用cancelCtx實現(xiàn)取消,另外使用定時器timer和過期時間deadline實現(xiàn)定時取消的功能。timerCtx在調(diào)用cancel方法,會先將內(nèi)部的cancelCtx取消,如果需要則將自己從cancelCtx祖先節(jié)點上移除,最后取消計時器。

WithDeadline

WithDeadline 用于設置一個絕對時間,表示在某個具體的時間點超時,例如 context.WithDeadline(parentContext, time.Now().Add(10 * time.Second)) 表示在當前時間的 10 秒后超時。

package main

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

func main() {
	HttpHandler()
}

func NewContextWithTimeout() (context.Context, context.CancelFunc) {
	return context.WithDeadline(context.Background(), time.Now().Add(10*time.Second))
}

func HttpHandler() {
	ctx, cancel := NewContextWithTimeout()
	defer cancel()
	deal(ctx)
}

func deal(ctx context.Context) {
	for i := 0; i < 10; i++ {
		time.Sleep(1 * time.Second)
		select {
		case <-ctx.Done():
			fmt.Println(ctx.Err())
			return
		default:
			fmt.Printf("deal time is %d\n", i)
		}
	}
}

WithTimeout

WithTimeout 用于設置一個相對時間,表示在多長時間后超時,例如 context.WithTimeout(parentContext, 5 * time.Second) 表示在 5 秒后超時。

package main

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

func main() {
	HttpHandler()
}

func NewContextWithTimeout() (context.Context, context.CancelFunc) {
	return context.WithTimeout(context.Background(), 3*time.Second)
}

func HttpHandler() {
	ctx, cancel := NewContextWithTimeout()
	defer cancel()
	deal(ctx)
}

func deal(ctx context.Context) {
	for i := 0; i < 10; i++ {
		time.Sleep(1 * time.Second)
		select {
		case <-ctx.Done():
			fmt.Println(ctx.Err())
			return
		default:
			fmt.Printf("deal time is %d\n", i)
		}
	}
}

總結(jié)

context主要用于父子任務之間的同步取消信號,本質(zhì)上是一種協(xié)程調(diào)度的方式。另外在使用context時有兩點值得注意:上游任務僅僅使用context通知下游任務不再需要,但不會直接干涉和中斷下游任務的執(zhí)行,由下游任務自行決定后續(xù)的處理操作,也就是說context的取消操作是無侵入的;context是線程安全的,因為context本身是不可變的(immutable),因此可以放心地在多個協(xié)程中傳遞使用。

到此這篇關于GO語言Context的作用及各種使用方法的文章就介紹到這了,更多相關GO語言Context使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Golang實現(xiàn)EasyCache緩存庫實例探究

    Golang實現(xiàn)EasyCache緩存庫實例探究

    這篇文章主要為大家介紹了Golang實現(xiàn)EasyCache緩存庫實例探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2024-01-01
  • go語言接口的定義和實現(xiàn)簡單分享

    go語言接口的定義和實現(xiàn)簡單分享

    這篇文章主要介紹了go語言接口的定義和實現(xiàn)簡單分享的相關資料,需要的朋友可以參考下
    2023-08-08
  • 一文詳解Golang中的切片數(shù)據(jù)類型

    一文詳解Golang中的切片數(shù)據(jù)類型

    這篇文章主要介紹了一文詳解Golang中的切片數(shù)據(jù)類型,切片是一個種特殊的數(shù)組。是對數(shù)組的一個連續(xù)片段的引用,所以切片是一個引用類型
    2022-09-09
  • Golang協(xié)程池的實現(xiàn)與應用

    Golang協(xié)程池的實現(xiàn)與應用

    這篇文章主要介紹了Golang協(xié)程池的實現(xiàn)與應用,使用協(xié)程池的好處是減少在創(chuàng)建和銷毀協(xié)程上所花的時間以及資源的開銷,解決資源不足的問題,需要詳細了解可以參考下文
    2023-05-05
  • 詳解Golang中Requests包的使用

    詳解Golang中Requests包的使用

    Go的net/http包雖然功能強大、用途也廣告,但要想正確的使用請求的客戶端是非常繁瑣的,所以本文和大家分享一個高效的HTTP的請求包carlmjohnson/requests的使用,需要的小伙伴可以了解一下
    2023-06-06
  • go?分布式鎖簡單實現(xiàn)實例詳解

    go?分布式鎖簡單實現(xiàn)實例詳解

    這篇文章主要為大家介紹了go?分布式鎖簡單實現(xiàn)實例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-09-09
  • 詳解Go 創(chuàng)建命令行工具的方法

    詳解Go 創(chuàng)建命令行工具的方法

    這篇文章主要介紹了詳解Go 創(chuàng)建命令行工具,需要的朋友可以參考下
    2020-12-12
  • Go實現(xiàn)一個配置包詳解

    Go實現(xiàn)一個配置包詳解

    在現(xiàn)代軟件開發(fā)中,配置文件是不可或缺的一部分。在編寫 Go 項目時,程序的靈活性和可擴展性都需要依賴于配置文件的加載。本文就來探究下在 Go 項目中如何更加方便的加載和管理配置,感興趣的朋友跟著小編一起來學習吧
    2023-04-04
  • Golang中的int類型和uint類型到底有多大?

    Golang中的int類型和uint類型到底有多大?

    int和uint類型在我們?nèi)粘i_發(fā)中經(jīng)常會用到,但有個疑問就是這兩個類型有多大,通過各種嘗試最終得到了答案,所以下面這篇文章主要給大家介紹了關于Golang中的int類型和uint類型到底有多大的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下。
    2017-12-12
  • Golang爬蟲框架 colly的使用

    Golang爬蟲框架 colly的使用

    本文主要介紹了Golang爬蟲框架 colly的使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-07-07

最新評論