« Programmation en Go/Goroutines » : différence entre les versions

Un livre de Wikilivres.
Contenu supprimé Contenu ajouté
Surkål (discussion | contributions)
DannyS712 (discussion | contributions)
m <source> -> <syntaxhighlight> (phab:T237267)
Ligne 8 : Ligne 8 :
Le mot clé '''go''' permet de lancer un appel de fonction en une goroutine, et de ne pas attendre le résultat:
Le mot clé '''go''' permet de lancer un appel de fonction en une goroutine, et de ne pas attendre le résultat:


<source lang="go"> go list.Sort() // trie une liste en parallèle</source>
<syntaxhighlight lang="go"> go list.Sort() // trie une liste en parallèle</syntaxhighlight>


Il est courant d'utiliser une fonction littérale pour appeler une goroutine:
Il est courant d'utiliser une fonction littérale pour appeler une goroutine:


<source lang="go">
<syntaxhighlight lang="go">
go func(arguments, ...) {
go func(arguments, ...) {
commandes...
commandes...
} (paramètres, ...)
} (paramètres, ...)
</syntaxhighlight>
</source>


== Les canaux (de communication) ==
== Les canaux (de communication) ==
Ligne 23 : Ligne 23 :
On peut créer un canal avec make:
On peut créer un canal avec make:


<source lang="go">
<syntaxhighlight lang="go">
c := make(chan int)
c := make(chan int)
</syntaxhighlight>
</source>


Ensuite on peut envoyer et recevoir des données du type précisé, et la première donnée reçue est la première donnée envoyée. (''First In First Out'')
Ensuite on peut envoyer et recevoir des données du type précisé, et la première donnée reçue est la première donnée envoyée. (''First In First Out'')
Ligne 33 : Ligne 33 :
Dans cet exemple, on lance une goroutine et on attend sa fin en recevant le signal qu'elle va envoyer:
Dans cet exemple, on lance une goroutine et on attend sa fin en recevant le signal qu'elle va envoyer:


<source lang="go">
<syntaxhighlight lang="go">
go func() {
go func() {
list.Sort()
list.Sort()
Ligne 40 : Ligne 40 :
blahBlahPendantUnMoment()
blahBlahPendantUnMoment()
<-c // Attend la fin du tri de la liste à la réception du signal
<-c // Attend la fin du tri de la liste à la réception du signal
</syntaxhighlight>
</source>


== Canaux avec tampon ==
== Canaux avec tampon ==
Ligne 50 : Ligne 50 :
Dans l'exemple suivant, MaxTaches tâches peuvent se dérouler en parallèle:
Dans l'exemple suivant, MaxTaches tâches peuvent se dérouler en parallèle:


<source lang="go">
<syntaxhighlight lang="go">
var sem = make(chan int, MaxTaches)
var sem = make(chan int, MaxTaches)


Ligne 65 : Ligne 65 :
}
}
}
}
</syntaxhighlight>
</source>


La syntaxe suivante permet de savoir si une case est disponible dans le canal:
La syntaxe suivante permet de savoir si une case est disponible dans le canal:


<source lang="go"> v,ok = <- canal</source>
<syntaxhighlight lang="go"> v,ok = <- canal</syntaxhighlight>


== Select ==
== Select ==
Ligne 77 : Ligne 77 :
Voici sa syntaxe:
Voici sa syntaxe:


<source lang="go">
<syntaxhighlight lang="go">
select {
select {
case canal <- valeur: commandes...
case canal <- valeur: commandes...
Ligne 84 : Ligne 84 :
default: ...
default: ...
}
}
</syntaxhighlight>
</source>


Les différentes alternatives sont évaluées dans l'ordre de leur écriture, la première réception ou émission dans un canal déclenche l'exécution des commandes correspondant à l'alternative. Si aucune de ces opérations ne réussit, le cas par défaut est exécuté, sinon l'opération bloque jusqu'à la réception ou l'envoi d'une donnée.
Les différentes alternatives sont évaluées dans l'ordre de leur écriture, la première réception ou émission dans un canal déclenche l'exécution des commandes correspondant à l'alternative. Si aucune de ces opérations ne réussit, le cas par défaut est exécuté, sinon l'opération bloque jusqu'à la réception ou l'envoi d'une donnée.

Version du 16 avril 2020 à 09:54

Définition

Une goroutine est un fil d'exécution tournant en parallèle avec d'autres goroutines à l'intérieur du même espace d'adressage (le processus).

Les goroutines permettent de paralléliser des tâches en les répartissant sur plusieurs coeurs ou processeurs. Le mot clé go permet de lancer un appel de fonction en une goroutine, et de ne pas attendre le résultat:

 go list.Sort() // trie une liste en parallèle

Il est courant d'utiliser une fonction littérale pour appeler une goroutine:

 go func(arguments, ...) {
   commandes...
 } (paramètres, ...)

Les canaux (de communication)

Un canal est un type de base de Go, et se déclare en plaçant chan (comme channel ou canal en anglais) avant le type de ses éléments. On peut créer un canal avec make:

 c := make(chan int)

Ensuite on peut envoyer et recevoir des données du type précisé, et la première donnée reçue est la première donnée envoyée. (First In First Out)

On dit qu'on envoie une donnée à travers un canal avec canal<-valeur et qu'on reçoit une donnée d'un canal avec = <-canal.

Dans cet exemple, on lance une goroutine et on attend sa fin en recevant le signal qu'elle va envoyer:

 go func() {
    list.Sort()
    c <- 1  // Envoie un signal, la valeur importe peu
 }()
 blahBlahPendantUnMoment()
 <-c   // Attend la fin du tri de la liste à la réception du signal

Canaux avec tampon

On peut créer un canal avec un tampon en fournissant la taille du tampon en argument de make().

Lorsque le canal n'a pas de tampon, la goroutine qui enfile une valeur doit attendre qu'une autre goroutine dépile cette valeur. En revanche, avec un tampon, la goroutine qui enfile une donnée attend seulement que le tampon dispose d'une case vide pour y mettre la donnée.

Dans l'exemple suivant, MaxTaches tâches peuvent se dérouler en parallèle:

 var sem = make(chan int, MaxTaches)

 func handle(r *Requete) {
    sem <- 1    // attend que sem soit disponible
    process(r)  // cela peut prendre un certain temps.
    <-sem       // cela permet à la prochaine tâche de démarrer
 }
 
 func Serve(file chan *Requete) {
    for {
        requete := <-file
        go handle(requete)  // lance la goroutine
    }
 }

La syntaxe suivante permet de savoir si une case est disponible dans le canal:

 v,ok = <- canal

Select

Select est une structure de contrôle similaire à switch. Elle permet de gérer une multitude d'envois et de réceptions à travers des canaux différents.

Voici sa syntaxe:

 select {
 case canal <- valeur: commandes...
 case var = <-canal: ...
 case var := <-canal: ...
 default: ...
 }

Les différentes alternatives sont évaluées dans l'ordre de leur écriture, la première réception ou émission dans un canal déclenche l'exécution des commandes correspondant à l'alternative. Si aucune de ces opérations ne réussit, le cas par défaut est exécuté, sinon l'opération bloque jusqu'à la réception ou l'envoi d'une donnée.

Le choix entre les différentes alternatives est basé sur un processus pseudo-aléatoire.

Enfin, une structure select sans aucune alternative bloque éternellement.

Définir le nombre de processeurs

En définissant la variable d'environnement GOMAXPROCS comme étant égale au moins au nombre de processeurs, ou en appelant runtime.GOMAXPROCS() avec ce nombre, on peut répartir les goroutines sur les différents cœurs ou processeurs sur un ordinateur particulier.