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 !
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.
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{} }
字段 | 含义 |
---|---|
Deadline | 返回一个time.Time,表示当前Context应该结束的时间,ok则表示有结束时间 |
Done | 当Context被取消或者超时时候返回的一个close的channel,告诉给context相关的函数要停止当前工作然后返回了。(这个有点像全局广播) |
Err | context被取消的原因 |
Value | context实现共享数据存储的地方,是协程安全的(还记得之前有说过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{} }
Ensuite, la bibliothèque fournit 4 implémentations de contexte avec lesquelles tout le monde peut jouer
implémentation | Structure | Fonction | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
emptyCtx | type emptyCtx int td> | Contexte complètement vide, les fonctions implémentées renvoient également nil, elles implémentent simplement l'interface Context | ||||||||||||||
cancelCtx | type CancelCtx struct { Contexte mu sync.Mutex
| < td>Hérite du contexte et implémente également l'interface d'annulation|||||||||||||||
timerCtx | type 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 | < /tr>||||||||||||||
valueCtx | tapez valueCtx struct {<🎜>Contexte<🎜> clé, interface val{}<🎜 >} | Données qui stockent les paires clé-valeur |
为了更方便的创建Context,包里头定义了Background来作为所有Context的根,它是一个emptyCtx的实例。
var ( background = new(emptyCtx) todo = new(emptyCtx) // ) func Background() Context { return background }
你可以认为所有的Context是树的结构,Background是树的根,当任一Context被取消的时候,那么继承它的Context 都将被回收。
实现源码:
func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { c := newCancelCtx(parent) propagateCancel(parent, &c) return &c, func() { c.cancel(true, Canceled) } }
实战场景:
执行一段代码,控制执行到某个度的时候,整个程序结束。
吃汉堡比赛,奥特曼每秒吃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 }
输出:
我吃了 1 个汉堡 我吃了 3 个汉堡 我吃了 5 个汉堡 我吃了 9 个汉堡 我吃了 10 个汉堡 正在统计结果。。。 耗时 6 秒,吃了 10 个汉堡
实现源码:
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)) }
实战场景:
执行一段代码,控制执行到某个时间的时候,整个程序结束。
吃汉堡比赛,奥特曼每秒吃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) } }
输出:
我吃了 1 个汉堡 我吃了 3 个汉堡 我吃了 5 个汉堡 我吃了 9 个汉堡 我吃了 10 个汉堡 我吃了 13 个汉堡 我吃了 13 个汉堡 我吃了 13 个汉堡 我吃了 14 个汉堡 我吃了 14 个汉堡 stop
实现源码:
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} }
实战场景:
携带关键信息,为全链路提供线索,比如接入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) }
输出:
traceID: 88888888 -session: 1
不多就一个。
Context要是全链路函数的第一个参数。
func myTest(ctx context.Context) { ... }
(写好了竟然忘记发送了。。。汗)
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!