Maison > développement back-end > Golang > Explication détaillée du contexte Golang

Explication détaillée du contexte Golang

藏色散人
Libérer: 2020-09-10 09:30:29
avant
4033 Les gens l'ont consulté

Ce qui suit est une explication détaillée du contexte de Golang à partir de la colonne tutoriel golang J'espère que cela sera utile aux amis dans le besoin !

Explication détaillée du contexte Golang

Avant-propos

Oui, aujourd'hui je Au départ, je voulais sortir et jouer. J'ai acheté un billet de train et j'ai encore dormi trop longtemps. . Il n'y a aucun moyen, c'est peut-être la volonté de Dieu, je dois donc résumer le contexte du golang, en espérant faire une rupture avec le contexte.

Dans l'entreprise, lorsque nous écrivons divers services, nous devons utiliser le Contexte comme premier paramètre. Au début, je pensais qu'il était principalement utilisé pour le dépannage et le suivi des liens complets. Mais avec plus de contacts, il s’avère que c’est bien plus que cela.

Texte

1. Explication détaillée du contexte

1.1 Fond de génération

Avant la version 1.7, le contexte n'était toujours pas programmé (y compris golang.org/ x /net/context), l'équipe golang a trouvé que le contexte est assez facile à utiliser et est utilisé dans de nombreux endroits, il y a donc été incorporé La version 1.7 est officiellement entrée dans la bibliothèque standard.

Postures d'utilisation courantes du contexte :
1. En programmation Web, une requête correspond à une interaction de données entre plusieurs goroutines
2. Contrôle du délai d'attente
3. 1.2 La structure sous-jacente du contexte

type Context interface {
    Deadline() (deadline time.Time, ok bool)
    Done() <-chan struct{}
    Err() error
    Value(key interface{}) interface{}
}
Copier après la connexion

Voici la structure de données sous-jacente du Context Analysons-la :

En même temps, le package définit également l'interface qui doit être. implémenté pour fournir la fonction d'annulation. Cela est principalement dû au fait que le « signal d'annulation et le signal de temporisation » mentionnés plus loin doivent être implémentés.
字段含义
Deadline返回一个time.Time,表示当前Context应该结束的时间,ok则表示有结束时间
Done当Context被取消或者超时时候返回的一个close的channel,告诉给context相关的函数要停止当前工作然后返回了。(这个有点像全局广播)
Errcontext被取消的原因
Valuecontext实现共享数据存储的地方,是协程安全的(还记得之前有说过map是不安全的?所以遇到map的结构,如果不是sync.Map,需要加锁来进行操作)
// A canceler is a context type that can be canceled directly. The
// implementations are *cancelCtx and *timerCtx.
type canceler interface {
	cancel(removeFromParent bool, err error)
	Done() <-chan struct{}
}
Copier après la connexion

Ensuite, la bibliothèque fournit 4 implémentations de contexte avec lesquelles tout le monde peut jouer

< td>Hérite du contexte et implémente également l'interface d'annulation< /tr>
implémentationStructureFonction
emptyCtxtype emptyCtx intContexte complètement vide, les fonctions implémentées renvoient également nil, elles implémentent simplement l'interface Context
cancelCtxtype CancelCtx struct {

Contexte

mu sync.Mutex
实现结构体作用
emptyCtxtype emptyCtx int完全空的Context,实现的函数也都是返回nil,仅仅只是实现了Context的接口
cancelCtxtype cancelCtx struct {
Context
mu sync.Mutex
done chan struct{}

children map[canceler]struct{}
err error
}
继承自Context,同时也实现了canceler接口
timerCtxtype timerCtx struct {
cancelCtx
timer *time.Timer // Under cancelCtx.mu.
deadline time.Time
}
继承自cancelCtx,增加了timeout机制
valueCtxtype valueCtx struct {
Context
key, val interface{}
}
存储键值对的数据
done chan struct{}<🎜> <🎜> children map[canceler]struct{}<🎜> erreur d'erreur<🎜 > }
timerCtxtype timerCtx struct { <🎜> CancelCtx<🎜> timer *time.Timer // Sous CancelCtx.mu.<🎜> date limite time.Time<🎜>} <🎜> hérite de <🎜>cancelCtx<🎜>, ajout d'un mécanisme de délai d'attente
valueCtxtapez valueCtx struct {<🎜>Contexte<🎜> clé, interface val{}<🎜 >} Données qui stockent les paires clé-valeur

1.3 context的创建

为了更方便的创建Context,包里头定义了Background来作为所有Context的根,它是一个emptyCtx的实例。

var (
    background = new(emptyCtx)
    todo       = new(emptyCtx) // 
)

func Background() Context {
    return background
}
Copier après la connexion

你可以认为所有的Context是树的结构,Background是树的根,当任一Context被取消的时候,那么继承它的Context 都将被回收。

2.context实战应用

2.1 WithCancel

实现源码:

func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
	c := newCancelCtx(parent)
	propagateCancel(parent, &c)
	return &c, func() { c.cancel(true, Canceled) }
}
Copier après la connexion

实战场景:
执行一段代码,控制执行到某个度的时候,整个程序结束。

吃汉堡比赛,奥特曼每秒吃0-5个,计算吃到10的用时
实战代码:

func main() {
	ctx, cancel := context.WithCancel(context.Background())
	eatNum := chiHanBao(ctx)
	for n := range eatNum {
		if n >= 10 {
			cancel()
			break
		}
	}

	fmt.Println("正在统计结果。。。")
	time.Sleep(1 * time.Second)
}

func chiHanBao(ctx context.Context) <-chan int {
	c := make(chan int)
	// 个数
	n := 0
	// 时间
	t := 0
	go func() {
		for {
			//time.Sleep(time.Second)
			select {
			case <-ctx.Done():
				fmt.Printf("耗时 %d 秒,吃了 %d 个汉堡 \n", t, n)
				return
			case c <- n:
				incr := rand.Intn(5)
				n += incr
				if n >= 10 {
					n = 10
				}
				t++
				fmt.Printf("我吃了 %d 个汉堡\n", n)
			}
		}
	}()

	return c
}
Copier après la connexion

输出:

我吃了 1 个汉堡
我吃了 3 个汉堡
我吃了 5 个汉堡
我吃了 9 个汉堡
我吃了 10 个汉堡
正在统计结果。。。
耗时 6 秒,吃了 10 个汉堡
Copier après la connexion

2.2 WithDeadline & WithTimeout

实现源码:

func WithDeadline(parent Context, d time.Time) (Context, CancelFunc) {
	if cur, ok := parent.Deadline(); ok && cur.Before(d) {
		// The current deadline is already sooner than the new one.
		return WithCancel(parent)
	}
	c := &timerCtx{
		cancelCtx: newCancelCtx(parent),
		deadline:  d,
	}
	propagateCancel(parent, c)
	dur := time.Until(d)
	if dur <= 0 {
		c.cancel(true, DeadlineExceeded) // deadline has already passed
		return c, func() { c.cancel(true, Canceled) }
	}
	c.mu.Lock()
	defer c.mu.Unlock()
	if c.err == nil {
		c.timer = time.AfterFunc(dur, func() {
			c.cancel(true, DeadlineExceeded)
		})
	}
	return c, func() { c.cancel(true, Canceled) }
}

func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {
	return WithDeadline(parent, time.Now().Add(timeout))
}
Copier après la connexion

实战场景:
执行一段代码,控制执行到某个时间的时候,整个程序结束。

吃汉堡比赛,奥特曼每秒吃0-5个,用时10秒,可以吃多少个
实战代码:

func main() {
    // ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(10))
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	chiHanBao(ctx)
	defer cancel()
}

func chiHanBao(ctx context.Context) {
	n := 0
	for {
		select {
		case <-ctx.Done():
			fmt.Println("stop \n")
			return
		default:
			incr := rand.Intn(5)
			n += incr
			fmt.Printf("我吃了 %d 个汉堡\n", n)
		}
		time.Sleep(time.Second)
	}
}
Copier après la connexion

输出:

我吃了 1 个汉堡
我吃了 3 个汉堡
我吃了 5 个汉堡
我吃了 9 个汉堡
我吃了 10 个汉堡
我吃了 13 个汉堡
我吃了 13 个汉堡
我吃了 13 个汉堡
我吃了 14 个汉堡
我吃了 14 个汉堡
stop
Copier après la connexion

2.3 WithValue

实现源码:

func WithValue(parent Context, key, val interface{}) Context {
	if key == nil {
		panic("nil key")
	}
	if !reflect.TypeOf(key).Comparable() {
		panic("key is not comparable")
	}
	return &valueCtx{parent, key, val}
}
Copier après la connexion

实战场景:
携带关键信息,为全链路提供线索,比如接入elk等系统,需要来一个trace_id,那WithValue就非常适合做这个事。
实战代码:

func main() {
	ctx := context.WithValue(context.Background(), "trace_id", "88888888")
	// 携带session到后面的程序中去
	ctx = context.WithValue(ctx, "session", 1)

	process(ctx)
}

func process(ctx context.Context) {
	session, ok := ctx.Value("session").(int)
	fmt.Println(ok)
	if !ok {
		fmt.Println("something wrong")
		return
	}

	if session != 1 {
		fmt.Println("session 未通过")
		return
	}

	traceID := ctx.Value("trace_id").(string)
	fmt.Println("traceID:", traceID, "-session:", session)
}
Copier après la connexion

输出:

traceID: 88888888 -session: 1
Copier après la connexion

3.context建议

不多就一个。

Context要是全链路函数的第一个参数

func myTest(ctx context.Context)  {
    ...
}
Copier après la connexion

(写好了竟然忘记发送了。。。汗)

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:csdn.net
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal