Table des matières
Canal Golang approfondi : principes de mise en œuvre et suggestions d'optimisation des performances
Utilisation de base de la chaîne
Fonction d'implémentation sous-jacente du canal
Structure des chaînes
Envoi de données de chaîne
Réception des données de la chaîne
Implémentation du tampon en anneau de canal
Écriture tampon
Lecture du tampon
Résumé
Leapcell : La meilleure plateforme sans serveur pour les applications Web Golang
Maison développement back-end Golang Go Channel déverrouillé : comment ils fonctionnent

Go Channel déverrouillé : comment ils fonctionnent

Jan 17, 2025 am 02:11 AM

Canal Golang approfondi : principes de mise en œuvre et suggestions d'optimisation des performances

Le canal de Golang est un élément clé de son modèle de concurrence CSP et un pont de communication entre les Goroutines. Channel est fréquemment utilisé dans Golang et il est crucial d'avoir une compréhension approfondie de ses principes de mise en œuvre internes. Cet article analysera l'implémentation sous-jacente de Channel basée sur le code source Go 1.13.

Utilisation de base de la chaîne

Avant d'analyser formellement la mise en œuvre de Channel, passons en revue son utilisation de base :

package main
import "fmt"

func main() {
    c := make(chan int)

    go func() {
        c <- 1 // 发送操作
    }()

    x := <-c // 接收操作
    fmt.Println(x)
}
Copier après la connexion
Copier après la connexion
Copier après la connexion

Ce code montre deux opérations de base de Channel :

  • Opération d'envoi : c <- 1
  • Opération de réception : x := <-c

Le canal est divisé en canal tamponné et canal non tamponné. Le code ci-dessus utilise un canal non tamponné. Dans un canal non tamponné, si aucun autre Goroutine ne reçoit actuellement de données, l'expéditeur bloquera l'instruction d'envoi.

Vous pouvez spécifier la taille du tampon lors de l'initialisation du canal. Par exemple, make(chan int, 2) spécifie que la taille du tampon est de 2. Avant que le tampon ne soit plein, l'expéditeur peut envoyer des données sans blocage sans attendre que le destinataire soit prêt. Mais si le tampon est plein, l'expéditeur bloquera toujours.

Fonction d'implémentation sous-jacente du canal

Avant de plonger dans le code source de Channel, vous devez trouver l'emplacement d'implémentation spécifique de Channel dans Golang. Lors de l'utilisation de Channel, les fonctions sous-jacentes telles que runtime.makechan, runtime.chansend et runtime.chanrecv sont en fait appelées.

Vous pouvez utiliser la commande go tool compile -N -l -S hello.go pour convertir le code en instructions d'assemblage, ou utiliser l'outil en ligne Compiler Explorer (par exemple : go.godbolt.org/z/3xw5Cj). En analysant la notice de montage, on peut retrouver :

  • make(chan int) correspond à la fonction runtime.makechan.
  • c <- 1 correspond à la fonction runtime.chansend.
  • x := <-c correspond à la fonction runtime.chanrecv.

L'implémentation de ces fonctions se trouve dans le fichier runtime/chan.go du code source de Go.

Structure des chaînes

make(chan int) sera converti en fonction runtime.makechan par le compilateur, et sa signature de fonction est la suivante :

func makechan(t *chantype, size int) *hchan
Copier après la connexion
Copier après la connexion
Copier après la connexion

Parmi eux, t *chantype est le type d'élément Channel, size int est la taille du tampon spécifiée par l'utilisateur (0 si non spécifiée) et la valeur de retour est *hchan. hchan est la structure de mise en œuvre interne de Channel in Golang, définie comme suit :

type hchan struct {
        qcount   uint           // 缓冲区中已放入元素的数量
        dataqsiz uint           // 用户构造Channel时指定的缓冲区大小
        buf      unsafe.Pointer // 缓冲区
        elemsize uint16         // 缓冲区中每个元素的大小
        closed   uint32         // Channel是否关闭,==0表示未关闭
        elemtype *_type         // Channel元素的类型信息
        sendx    uint           // 缓冲区中发送元素的索引位置(发送索引)
        recvx    uint           // 缓冲区中接收元素的索引位置(接收索引)
        recvq    waitq          // 等待接收的Goroutine列表
        sendq    waitq          // 等待发送的Goroutine列表

        lock mutex
}
Copier après la connexion
Copier après la connexion

Les attributs de hchan sont grossièrement divisés en trois catégories :

  • Attributs liés au tampon : tels que buf, dataqsiz, qcount, etc. Lorsque la taille du tampon du canal n'est pas 0, le tampon est utilisé pour stocker les données à recevoir et est implémenté à l'aide d'un tampon en anneau.
  • Attributs liés à la file d'attente : recvq contient Goroutine en attente de réception de données, sendq contient Goroutine en attente d'envoi de données. waitqMise en œuvre à l'aide d'une liste doublement chaînée.
  • Autres attributs : tels que lock, elemtype, closed, etc.
La fonction

makechan effectue principalement des contrôles de légalité et l'allocation de mémoire d'attributs tels que les tampons et hchan, qui ne seront pas abordés en profondeur ici.

Sur la base d'une simple analyse de l'attribut hchan, on peut voir qu'il existe deux composants importants : le tampon et la file d'attente. Tous les comportements et implémentations de hchan tournent autour de ces deux composants.

Envoi de données de chaîne

Les processus d'envoi et de réception de Channel sont très similaires. Analysez d'abord le processus d'envoi de Channel (par exemple c <- 1).

Lorsque

essaie d'envoyer des données au canal, si la file d'attente recvq n'est pas vide, une Goroutine en attente de réception de données sera retirée de l'en-tête recvq et les données seront envoyées directement à la Goroutine. Le code est le suivant :

package main
import "fmt"

func main() {
    c := make(chan int)

    go func() {
        c <- 1 // 发送操作
    }()

    x := <-c // 接收操作
    fmt.Println(x)
}
Copier après la connexion
Copier après la connexion
Copier après la connexion

recvq Contient Goroutine en attente de réception de données. Lorsqu'une Goroutine utilise une opération de réception (telle que x := <-c), si sendq n'est pas vide à ce moment, une Goroutine sera extraite de sendq et les données lui seront envoyées.

Si recvq est vide, cela signifie qu'il n'y a pas de Goroutine en attente de recevoir des données à ce moment-là, et la chaîne essaiera de mettre les données dans le tampon :

func makechan(t *chantype, size int) *hchan
Copier après la connexion
Copier après la connexion
Copier après la connexion

La fonction de ce code est très simple, c'est de mettre des données dans le tampon. Ce processus implique le fonctionnement d'un tampon en anneau, dataqsiz représente la taille du tampon spécifiée par l'utilisateur (la valeur par défaut est 0 si elle n'est pas spécifiée).

Si un canal non tamponné est utilisé ou si le tampon est plein (c.qcount == c.dataqsiz), les données à envoyer et la Goroutine actuelle seront regroupées dans un objet sudog, placé dans sendq, et le courant Goroutine sera configuré pour attendre Statut :

type hchan struct {
        qcount   uint           // 缓冲区中已放入元素的数量
        dataqsiz uint           // 用户构造Channel时指定的缓冲区大小
        buf      unsafe.Pointer // 缓冲区
        elemsize uint16         // 缓冲区中每个元素的大小
        closed   uint32         // Channel是否关闭,==0表示未关闭
        elemtype *_type         // Channel元素的类型信息
        sendx    uint           // 缓冲区中发送元素的索引位置(发送索引)
        recvx    uint           // 缓冲区中接收元素的索引位置(接收索引)
        recvq    waitq          // 等待接收的Goroutine列表
        sendq    waitq          // 等待发送的Goroutine列表

        lock mutex
}
Copier après la connexion
Copier après la connexion

goparkunlock déverrouillera le mutex d'entrée et suspendra le Goroutine actuel, le mettant dans un état d'attente. gopark et goready apparaissent par paires et sont des opérations réciproques.

Du point de vue de l'utilisateur, après avoir appelé gopark, l'instruction de code pour l'envoi de données sera bloquée.

Réception des données de la chaîne

Le processus de réception de Channel est fondamentalement similaire au processus d'envoi, je n'entrerai donc pas dans les détails ici. Les opérations liées au tampon impliquées dans le processus de réception seront décrites en détail ultérieurement.

Il convient de noter que l'ensemble du processus d'envoi et de réception de Channel est verrouillé à l'aide de runtime.mutex. runtime.mutex est un verrou léger couramment utilisé dans le code source lié à l'exécution. L'ensemble du processus n'est pas la solution sans verrou la plus efficace. Il y a un problème concernant la chaîne sans verrouillage dans Golang : go/issues#8899.

Implémentation du tampon en anneau de canal

Channel utilise un tampon en anneau pour mettre en cache les données écrites. Les tampons en anneau présentent de nombreux avantages et sont idéaux pour implémenter des files d'attente FIFO de longueur fixe.

L'implémentation du ring buffer dans Channel est la suivante :

Il y a deux variables liées au tampon dans

hchan : recvx et sendx. sendx représente un index inscriptible dans le tampon, et recvx représente un index lisible dans le tampon. Les éléments entre recvx et sendx représentent les données qui ont été normalement placées dans le tampon.

Go Channel Unlocked: How They Work

Vous pouvez directement utiliser buf[recvx] pour lire le premier élément de la file d'attente, et utiliser buf[sendx] = x pour mettre l'élément en fin de file d'attente.

Écriture tampon

Lorsque le tampon n'est pas plein, l'opération de mise des données dans le tampon est la suivante :

package main
import "fmt"

func main() {
    c := make(chan int)

    go func() {
        c <- 1 // 发送操作
    }()

    x := <-c // 接收操作
    fmt.Println(x)
}
Copier après la connexion
Copier après la connexion
Copier après la connexion

chanbuf(c, c.sendx) équivaut à c.buf[c.sendx]. Le processus ci-dessus est très simple, copiez simplement les données vers l'emplacement tampon sendx.

Ensuite, passez sendx à la position suivante. Si sendx atteint la dernière position, il est mis à 0, ce qui est une approche typique de bout en bout.

Lecture du tampon

Lorsque le tampon n'est pas plein, sendq doit également être vide (car si le tampon n'est pas plein, la Goroutine envoyant les données ne sera pas mise en file d'attente, mais mettra directement les données dans le tampon). À l'heure actuelle, la logique de lecture du canal chanrecv est relativement simple. Les données peuvent être lues directement à partir du tampon. C'est également un processus de déplacement de recvx, qui est fondamentalement le même que l'écriture du tampon ci-dessus.

Quand il y a une Goroutine en attente dans sendq, le tampon doit être plein à ce moment. A l'heure actuelle, la logique de lecture de Channel est la suivante :

func makechan(t *chantype, size int) *hchan
Copier après la connexion
Copier après la connexion
Copier après la connexion

ep est l'adresse correspondant à la variable qui reçoit les données (par exemple, dans x := <-c, ep est l'adresse de x). sg représente le premier sendq extrait de sudog. Dans le code :

  • typedmemmove(c.elemtype, ep, qp) signifie copier l'élément actuellement lisible dans le tampon à l'adresse de la variable réceptrice.
  • typedmemmove(c.elemtype, qp, sg.elem) signifie copier les données en attente d'envoi par Goroutine dans sendq dans le tampon. Parce que recv est exécuté plus tard, cela équivaut à placer les données dans sendq à la fin de la file d'attente.

En termes simples, ici Channel copie les premières données du tampon dans la variable de réception correspondante, et copie en même temps les éléments de sendq à la fin de la file d'attente, implémentant ainsi FIFO (premier entré, premier sorti) .

Résumé

Channel est l'une des fonctionnalités les plus couramment utilisées dans Golang. Comprendre son code source vous aidera à mieux utiliser et comprendre Channel. Dans le même temps, ne soyez pas trop superstitieux et comptez sur les performances de Channel. La conception actuelle de Channel a encore beaucoup de place pour l'optimisation.

Suggestions d'optimisation :

  • Utilisez un mécanisme de verrouillage plus léger ou un système sans verrouillage pour améliorer les performances.
  • Optimisez la gestion des tampons et réduisez l'allocation de mémoire et les opérations de copie.

Leapcell : La meilleure plateforme sans serveur pour les applications Web Golang

Go Channel Unlocked: How They Work

Enfin, je recommande une plateforme très adaptée au déploiement des services Go : Leapcell

  1. Prise en charge multilingue : Prend en charge le développement JavaScript, Python, Go ou Rust.
  2. Déployez gratuitement un nombre illimité de projets : ne payez que ce que vous utilisez, sans demande, sans frais.
  3. Extrêmement rentable : payez au fur et à mesure, pas de frais d'inactivité. Par exemple : 25 $ prend en charge 6,94 millions de requêtes avec un temps de réponse moyen de 60 millisecondes.
  4. Expérience de développement fluide : interface utilisateur intuitive pour une configuration facile ; pipeline CI/CD entièrement automatisé et intégration de GitOps ; métriques et journaux en temps réel pour des informations exploitables.
  5. Évolutivité facile et hautes performances : mise à l'échelle automatique pour gérer facilement une simultanéité élevée, zéro surcharge opérationnelle, concentration sur la construction.
Go Channel Unlocked: How They Work

Veuillez consulter la documentation pour plus d'informations !

Twitter de Leapcell : https://www.php.cn/link/7884effb9452a6d7a7a79499ef854afd

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!

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

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

Video Face Swap

Video Face Swap

Échangez les visages dans n'importe quelle vidéo sans effort grâce à notre outil d'échange de visage AI entièrement gratuit !

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Quelles sont les vulnérabilités de Debian OpenSSL Quelles sont les vulnérabilités de Debian OpenSSL Apr 02, 2025 am 07:30 AM

OpenSSL, en tant que bibliothèque open source largement utilisée dans les communications sécurisées, fournit des algorithmes de chiffrement, des clés et des fonctions de gestion des certificats. Cependant, il existe des vulnérabilités de sécurité connues dans sa version historique, dont certaines sont extrêmement nocives. Cet article se concentrera sur les vulnérabilités et les mesures de réponse communes pour OpenSSL dans Debian Systems. DebianopenSSL CONNUTS Vulnérabilités: OpenSSL a connu plusieurs vulnérabilités graves, telles que: la vulnérabilité des saignements cardiaques (CVE-2014-0160): cette vulnérabilité affecte OpenSSL 1.0.1 à 1.0.1F et 1.0.2 à 1.0.2 Versions bêta. Un attaquant peut utiliser cette vulnérabilité à des informations sensibles en lecture non autorisées sur le serveur, y compris les clés de chiffrement, etc.

Comment spécifier la base de données associée au modèle de Beego ORM? Comment spécifier la base de données associée au modèle de Beego ORM? Apr 02, 2025 pm 03:54 PM

Dans le cadre du cadre de beegoorm, comment spécifier la base de données associée au modèle? De nombreux projets Beego nécessitent que plusieurs bases de données soient opérées simultanément. Lorsque vous utilisez Beego ...

Transformant du développement frontal au développement back-end, est-il plus prometteur d'apprendre Java ou Golang? Transformant du développement frontal au développement back-end, est-il plus prometteur d'apprendre Java ou Golang? Apr 02, 2025 am 09:12 AM

Chemin d'apprentissage du backend: le parcours d'exploration du front-end à l'arrière-end en tant que débutant back-end qui se transforme du développement frontal, vous avez déjà la base de Nodejs, ...

Comment résoudre le problème de conversion de type user_id lors de l'utilisation du flux redis pour implémenter les files d'attente de messages dans le langage Go? Comment résoudre le problème de conversion de type user_id lors de l'utilisation du flux redis pour implémenter les files d'attente de messages dans le langage Go? Apr 02, 2025 pm 04:54 PM

Le problème de l'utilisation de Redessstream pour implémenter les files d'attente de messages dans le langage GO consiste à utiliser le langage GO et redis ...

Que dois-je faire si les étiquettes de structure personnalisées à Goland ne sont pas affichées? Que dois-je faire si les étiquettes de structure personnalisées à Goland ne sont pas affichées? Apr 02, 2025 pm 05:09 PM

Que dois-je faire si les étiquettes de structure personnalisées à Goland ne sont pas affichées? Lorsque vous utilisez Goland pour le développement du langage GO, de nombreux développeurs rencontreront des balises de structure personnalisées ...

Quelles bibliothèques sont utilisées pour les opérations du numéro de point flottantes en Go? Quelles bibliothèques sont utilisées pour les opérations du numéro de point flottantes en Go? Apr 02, 2025 pm 02:06 PM

La bibliothèque utilisée pour le fonctionnement du numéro de point flottante dans le langage go présente comment s'assurer que la précision est ...

Quel est le problème avec le fil de file d'attente dans GO's Crawler Colly? Quel est le problème avec le fil de file d'attente dans GO's Crawler Colly? Apr 02, 2025 pm 02:09 PM

Problème de threading de file d'attente dans Go Crawler Colly explore le problème de l'utilisation de la bibliothèque Crawler Crawler dans le langage Go, les développeurs rencontrent souvent des problèmes avec les threads et les files d'attente de demande. � ...

Comment configurer l'expansion automatique de MongoDB sur Debian Comment configurer l'expansion automatique de MongoDB sur Debian Apr 02, 2025 am 07:36 AM

Cet article présente comment configurer MongoDB sur Debian System pour réaliser une expansion automatique. Les étapes principales incluent la configuration de l'ensemble de répliques MongoDB et de la surveillance de l'espace disque. 1. Installation de MongoDB Tout d'abord, assurez-vous que MongoDB est installé sur le système Debian. Installez à l'aide de la commande suivante: SudoaptupDaSudoaptInstall-myongoDB-Org 2. Configuration de la réplique MongoDB Ensemble de répliques MongoDB assure la haute disponibilité et la redondance des données, ce qui est la base de la réalisation d'une expansion de capacité automatique. Démarrer le service MongoDB: Sudosystemctlstartmongodsudosys

See all articles