Sobes.tech
Middle

Qu'est-ce que le temps d'exécution (runtime) et comment fonctionne le planificateur (scheduler) ?

sobes.tech IA

Réponse de l'IA

Le temps d'exécution (runtime) en Go est l'environnement dans lequel s'exécutent les programmes Go. Il comprend :

  • Gestion de la mémoire : Le ramasse-miettes (garbage collector) gère automatiquement l'allocation et la libération de mémoire.
  • Planificateur (scheduler) : Gère l'exécution des goroutines sur les threads du système d'exploitation.
  • Appels système : Fournit une interface pour interagir avec le système d'exploitation.
  • Primitives de synchronisation : Canaux, mutex et autres mécanismes pour coordonner les goroutines.

Le planificateur Go implémente le modèle M:N (plusieurs goroutines sur plusieurs threads OS). Ses composants principaux :

  • G (Goroutine) : Un thread léger d'exécution, essentiellement une abstraction au-dessus d'une fonction.
  • M (Machine) : Un thread du système d'exploitation sur lequel s'exécutent les programmes Go.
  • P (Processor) : Un processeur logique associé à un thread OS. Il maintient une file d'attente locale runnable de goroutines.

Principe de fonctionnement du planificateur :

  1. Les goroutines (G) sont créées et ajoutées à une file d'attente globale ou locale runnable.
  2. Les threads OS (M) sont associés à des processeurs logiques (P). La quantité de P par défaut est égale au nombre de cœurs CPU (GOMAXPROCS).
  3. P prend une goroutine de sa file locale. Si la file locale est vide, P tente de "voler" (steal) des goroutines de la file d'un autre P ou de la file globale.
  4. M exécute la goroutine.
  5. Lorsqu'une goroutine se bloque (par exemple, lors de la lecture d'un canal sans données ou lors d'un appel système), M se désassocie de P, et P devient disponible pour exécuter une autre goroutine. La goroutine bloquée est mise en attente. Lorsqu'elle se débloque, elle redevient runnable et est remise dans la file.
  6. Si M se bloque dans un appel système, il ne retient pas P. Un nouveau M peut être créé ou un existant peut être utilisé pour que P puisse continuer à exécuter d'autres goroutines.

Cette approche permet d'utiliser efficacement les ressources du processeur et de faire évoluer facilement les tâches parallèles, en masquant la complexité de la gestion des threads OS pour le développeur.

// Exemple de création d'une goroutine
func myFunc() {
	// Code de la goroutine
}

func main() {
	go myFunc() // Démarrage de la goroutine
	// Le programme principal continue à s'exécuter en parallèle
}