Die folgende Kolumne enthält eine detaillierte Erklärung des Golang-Kontexts aus der Kolumne „Golang-Tutorial“. Ich hoffe, dass sie für Freunde hilfreich ist, die sie benötigen!
Ja, ich wollte heute rausgehen und spielen. Ich kaufte ein Zugticket und verschlafe erneut. . Es gibt keine Möglichkeit, vielleicht ist es Gottes Wille, also muss ich den Kontext von Golang zusammenfassen, in der Hoffnung, einen Bruch mit dem Kontext zu machen.
Text
1.Kontext Detaillierte Erklärung
Häufige Nutzungspositionen des Kontexts: 1. Bei der Webprogrammierung entspricht eine Anfrage der Dateninteraktion zwischen mehreren Goroutinen. 3. Kontextsteuerung.
1.2 Die zugrunde liegende Struktur des Kontexts die zugrunde liegende Datenstruktur:
Bedeutung
Deadline | gibt eine Zeit zurück. Zeit, die den Zeitpunkt angibt, zu dem der aktuelle Kontext enden soll, ok bedeutet, dass es eine Endzeit gibt |
---|---|
Ein geschlossener Kanal wird zurückgegeben, wenn der Kontext abgebrochen wird oder eine Zeitüberschreitung auftritt, und weist die kontextbezogenen Funktionen an, die aktuelle Arbeit zu stoppen und zurückzukehren. (Das ist ein bisschen wie eine globale Übertragung) | |
Der Grund, warum der Kontext abgebrochen wurde | |
context implementiert einen gemeinsamen Datenspeicher, der Coroutine-sicher ist (denken Sie daran, dass Map zuvor als unsicher galt). ?Wenn Sie also auf die Kartenstruktur stoßen und diese nicht sync.Map ist, müssen Sie sie für den Betrieb sperren) | |
Gleichzeitig definiert das Paket auch die Schnittstelle, die implementiert werden muss, um den Abbruch bereitzustellen Funktion. Dies liegt hauptsächlich daran, dass das später erwähnte „Abbruchsignal und Timeout-Signal“ implementiert werden muss. | Dann bietet die Bibliothek 4 Kontextimplementierungen, mit denen jeder spielen kann völlig leer Kontext, Implementierung Die Funktionen kehren auch zurück Null, sie implementieren nur die Kontextschnittstelle |
Context
mu sync.Mutexerror Deadline Time.Time | }Von | cancelCtx|
---|---|---|
valueCtx | Typ valueCtx struct { | Contextkey, val interface{} | }
1.3 context的创建为了更方便的创建Context,包里头定义了Background来作为所有Context的根,它是一个emptyCtx的实例。 var ( background = new(emptyCtx) todo = new(emptyCtx) // ) func Background() Context { return background } Nach dem Login kopieren 你可以认为所有的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) } } Nach dem Login kopieren 实战场景: 吃汉堡比赛,奥特曼每秒吃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 } Nach dem Login kopieren 输出: 我吃了 1 个汉堡 我吃了 3 个汉堡 我吃了 5 个汉堡 我吃了 9 个汉堡 我吃了 10 个汉堡 正在统计结果。。。 耗时 6 秒,吃了 10 个汉堡 Nach dem Login kopieren 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)) } Nach dem Login kopieren 实战场景: 吃汉堡比赛,奥特曼每秒吃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) } } Nach dem Login kopieren 输出: 我吃了 1 个汉堡 我吃了 3 个汉堡 我吃了 5 个汉堡 我吃了 9 个汉堡 我吃了 10 个汉堡 我吃了 13 个汉堡 我吃了 13 个汉堡 我吃了 13 个汉堡 我吃了 14 个汉堡 我吃了 14 个汉堡 stop Nach dem Login kopieren 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} } Nach dem Login kopieren 实战场景: 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) } Nach dem Login kopieren 输出: traceID: 88888888 -session: 1 Nach dem Login kopieren 3.context建议不多就一个。 Context要是全链路函数的第一个参数。 func myTest(ctx context.Context) { ... } Nach dem Login kopieren (写好了竟然忘记发送了。。。汗) |
Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung des Golang-Kontexts. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!