Go:context包

yimt發表於2020-10-20

Go:context包

1. 簡介

1.1. 作用

主要用Goroutine管理,停止Goroutine或之間引數傳遞。

1.2. 核心介面

type Context interface {
	Deadline() (deadline time.Time, ok bool)
	Done() <-chan struct{}
	Err() error
	Value(key interface{}) interface{}
}
方法說明
Deadline返回截止時間和是否存在截止時間
Done獲取完成chan
ErrDone關閉的原因,沒有關閉返回nil
Value獲取上下文中儲存的使用者值

2. 演示

2.1. WithCancel

上下文取消

package main

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

func main() {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	// 啟動工人去幹活
	go worker(ctx)

	time.Sleep(time.Second * 5)
	// 告訴工人停止幹活
	cancel()
	time.Sleep(time.Second * 1)
}

func worker(ctx context.Context) {
	for {
		select {
		case <-ctx.Done():
			fmt.Println("work over")
			return
		default:
			fmt.Println("at work")
			time.Sleep(time.Second * 1)
		}
	}
}

2.2. WithTimeout

上下文超時

package main

import (
	"context"
	"encoding/hex"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"
)

type Result struct {
	r   *http.Response
	err error
}

func main() {
	// 請求超時時間設定為10秒
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	res, err := httpGet(ctx)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := ioutil.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	fmt.Println(hex.Dump(data))
}

func httpGet(ctx context.Context) (*http.Response, error) {
	reqResult := make(chan Result, 1)
	go func() {
		res, err := http.Get("https://www.baidu.com")
		reqResult <- Result{res, err}
	}()

	select {
	case <-ctx.Done():
		return nil, ctx.Err()
	case result := <-reqResult:
		return result.r, nil
	}
}

2.3. WithDeadline

上下文截止時間

package main

import (
	"fmt"
	"golang.org/x/net/context"
	"time"
)

func main() {
	ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(time.Second * 5))
	defer cancel()

	select {
	case <-time.After(time.Second * 10):
		fmt.Println("time.After timeout")
	case <-ctx.Done():
		// 5秒過後執行,列印:context deadline exceeded
		fmt.Println(ctx.Err())
	}
}

2.4. WithValue

上下文傳參

package main

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

func main() {
	ctx := context.WithValue(context.Background(), "id", 1)
	go GetID(ctx)
	time.Sleep(1 * time.Second)
}

func GetID(ctx context.Context) {
	id, ok := ctx.Value("id").(int)
	if ok {
		fmt.Println(id)
	}
}

2.5. 組合寫法

package main

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

func main() {
	ctx, cancel := context.WithTimeout(context.Background(), 10 * time.Second)
	defer cancel()

	ctx = context.WithValue(ctx, "id", 1)

	ctx = context.WithValue(ctx, "name", "yimt1")
	// 會覆蓋上面值
	ctx = context.WithValue(ctx, "name", "yimt2")

	if id, ok := ctx.Value("id").(int); ok {
		fmt.Println(id)
	}

	if name, ok := ctx.Value("name").(string); ok {
		fmt.Println(name)
	}
}

相關文章