Prenez l'habitude d'écrire ensemble ! C'est le 9ème jour de ma participation au "Nuggets Daily New Plan · April Update Challenge", cliquez pour voir les détails de l'événement .
aller dans le contexte coroutinecontext
golang est context
principalement utilisé pour transférer des informations de contexte entre les goroutines, notamment : le signal d'annulation, le délai d'attente, la date limite, le kv, etc.
context
C'est une fonctionnalité qui est sortie après la 1.17
version golang
Problèmes résolus par le contexte
- Communication entre coroutines
Par exemple, dans une application Web, chaque requête est gérée par une coroutine. Bien sûr, pour cette coroutine qui traite les requêtes, nous démarrons généralement d'autres coroutines pour gérer d'autres services, tels que les opérations de base de données, l'authentification, la lecture et l'écriture de fichiers, etc. Ces coroutines sont indépendantes et nous ne pouvons pas percevoir comment les autres coroutines s'exécutent dans la coroutine actuelle. Le canal utilitaire channel
peut réaliser la fonction de communication
context
Essentiellement context.WithValue()
, channel
la communication passe également par
- Gestion du timeout des sous-coroutines
De même, dans les applications Web, notre processus principal réside toujours en mémoire. Chaque demande est traitée par une coroutine. Dans le processus de traitement des affaires, une autre coroutine peut être démarrée pour traiter d'autres services. Lorsque la sous-coroutine est anormale ou bloquée, il est impossible de remonter les informations à la coroutine de niveau supérieur. , la coroutine principale se bloquera si elle ne reçoit pas de retour. Le contexte peut très bien résoudre ce problème, et context
peut réaliser le timeout ou la sortie temporelle de la sous-coroutine ou de la coroutine descendante
Plusieurs méthodes et usages du contexte
context.WithCancel(context.Context)
WithCancel()
La méthode passe dans une instance de contexte vide, qui peut être utilisée directement context.Background()
, et renvoie un contexte et une fonction d'annulation. L' appel cancal()
transmettra des signaux à d'autres coroutines, et les sous-coroutines peuvent être fermées ou traitées après avoir reçu le signal
package main
import (
"context"
"fmt"
"time"
)
func worker(ctx context.Context) {
for {
select {
case <-ctx.Done():
return
default:
}
fmt.Println("worker...")
time.Sleep(time.Second * 1)
}
}
func main() {
ctx, cancal := context.WithCancel(context.Background())
go worker(ctx)
time.Sleep(time.Second * 5)
cancal()
fmt.Println("over ...")
}
复制代码
context.WithTimeout(context.Context,timeout)
Définissez un contexte qui expirera. Après l'instanciation, le compte à rebours commencera. Le moment venu, la cancel()
fonction sera automatiquement appelée pour notifier la sous-coroutine, ou la cancel()
notification peut être appelée manuellement. S'il y a des sous-coroutines dans la sous-coroutine, continuez à utiliser ce contexte, lorsque la coroutine principale envoie un signal d'annulation, tous ceux qui utilisent ce contexte seront notifiés
package main
import (
"context"
"fmt"
"time"
)
func worker(ctx context.Context) {
for {
select {
case <-ctx.Done():
return
default:
}
fmt.Println("worker...")
time.Sleep(time.Second * 1)
}
}
func main() {
ctx, cancal := context.WithTimeout(context.Background(), time.Second*2)
go worker(ctx)
time.Sleep(time.Second * 5)
cancal()
fmt.Println("over ...")
}
复制代码
context.WithDeadline(context.Context,(绝对时间)timeout)
Définissez un contexte qui expirera, la Timeout
différence est que le temps passé est un temps absolu. Lorsque l'heure spécifiée est atteinte, la cancel()
fonction sera automatiquement appelée pour notifier la sous-coroutine, ou la cancel()
notification peut être appelée manuellement. S'il y a des sous-coroutines dans la sous-coroutine, continuez à utiliser ce contexte, lorsque la coroutine principale envoie un signal d'annulation, tous ceux qui utilisent ce contexte seront notifiés
package main
import (
"context"
"fmt"
"time"
)
func worker(ctx context.Context) {
for {
select {
case <-ctx.Done():
return
default:
}
fmt.Println("worker...")
time.Sleep(time.Second * 1)
}
}
func main() {
ctx, cancal := context.WithDeadline(context.Background(), time.Now().Add(3 * time.Second))
go worker(ctx)
time.Sleep(time.Second * 5)
cancal()
fmt.Println("over ...")
}
复制代码
Communication de contexte entre coroutines :context.WithValue()
Jetez d'abord un coup d'œil à ce code
package main
import (
"context"
"fmt"
"time"
)
type CTXKEY string
func worker(ctx context.Context) {
// 在子协程中获取上下文信息
num, ok := ctx.Value(CTXKEY("num")).(string)
if !ok {
fmt.Println("invalid trace code")
}
fmt.Println(num)
for {
select {
case <-ctx.Done():
return
default:
}
fmt.Println("worker...")
time.Sleep(time.Second * 1)
}
}
func main() {
ctx, cancal := context.WithDeadline(context.Background(), time.Now().Add(3*time.Second))
// 利用上下文传一个 num = 1234567
// 实例化一个上下文
ctx = context.WithValue(ctx, CTXKEY("num"), "1234567")
go worker(ctx)
time.Sleep(time.Second * 5)
cancal()
fmt.Println("over ...")
}
复制代码
La communication entre coroutines se fait par le biais du contexte Si le projet est important, afin d'éviter la pollution des variables, en principe : la clé utilisée pour la communication du contexte doit personnaliser un type
type traceCode string;context.WithValue(context.Context,key,value)