Maison > Article > développement back-end > L'écriture simultanée sur « stdout » dans Go Thread-Safe est-elle ? Une analyse détaillée du comportement de « fmt.Fprintf ».
Écriture simultanée sur la sortie standard : analyse de la sécurité des threads
Dans une discussion récente, un morceau de code Go a été présenté, ce qui a déclenché un débat sur le thread sécurité lors de l'écriture simultanée sur la sortie standard. Le code en question est :
<code class="go">package main import ( "fmt" "os" "strings" ) func main() { x := strings.Repeat(" ", 1024) go func() { for { fmt.Fprintf(os.Stdout, x+"aa\n") } }() go func() { for { fmt.Fprintf(os.Stdout, x+"bb\n") } }() go func() { for { fmt.Fprintf(os.Stdout, x+"cc\n") } }() go func() { for { fmt.Fprintf(os.Stdout, x+"dd\n") } }() <-make(chan bool) }</code>
Considérations sur la sécurité des threads :
La question se pose de savoir si ce code est thread-safe lorsque plusieurs goroutines écrivent simultanément sur la sortie standard. Diverses sources et opinions sur le sujet ont été mentionnées, mais aucune réponse définitive n'a pu être trouvée. Approfondissons le sujet.
Comportement du package fmt :
Les fonctions du package fmt prennent simplement une implémentation io.Writer et appellent Write() dessus. Les fonctions elles-mêmes sont thread-safe, ce qui signifie que plusieurs appels simultanés aux fonctions fmt.F* sont sécurisés. Cependant, l'implémentation de l'écriture simultanée sur la sortie standard dépend du « rédacteur » spécifique utilisé.
Implémentations du « rédacteur » :
Deux catégories principales de « rédacteurs » sont pertinentes :
Sémantique POSIX :
Dans le cas des descripteurs de fichiers, POSIX nécessite l'écriture (2) appelle à être atomique lors de l'opération sur des fichiers normaux ou des liens symboliques. Cela signifie que dans notre cas, où stdout est supposé être un descripteur de fichier, les appels d'écriture doivent être atomiques.
Implémentation de la bibliothèque standard Go :
La bibliothèque standard Go les wrappers autour des descripteurs de fichiers et des sockets sont conçus pour mapper les opérations d'écriture 1 à 1 à l'objet sous-jacent. Cela élimine la possibilité que les appels d'écriture soient divisés ou collés ensemble.
Conclusion :
Sur la base des informations disponibles et de la sémantique sous-jacente de l'appel POSIX write(2) , le code fourni n'est pas soumis à des courses de données. Cependant, la sortie écrite dans le descripteur de fichier sous-jacent peut être mélangée dans un ordre imprévisible. Ce comportement est influencé par des facteurs tels que la version du noyau du système d'exploitation, la version Go, le matériel et la charge du système.
Pour garantir que la sortie de chaque appel fmt.Fprint* spécifique apparaît comme une pièce contiguë dans la sortie résultante , il est recommandé de sérialiser les appels à l'aide d'un verrou ou en utilisant le package log, qui fournit ses propres mécanismes de verrouillage.
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!