Optimisation des performances des applications Go : conseils et exemples

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Introduction : Pourquoi la performance de Go est importante

Go (Golang) est un langage compilé à typage statique conçu pour les systèmes à forte charge. Cependant, même avec Go, vous pouvez écrire une application lente si vous ne tenez pas compte des spécificités du fonctionnement du ramasse-miettes (GC), de la gestion de la mémoire et de la concurrence. Dans cet article, nous allons détailler les techniques d'optimisation clés : du profilage au réglage fin du GC. Vous apprendrez à transformer un code "brut" en une solution performante prête pour la production.



1. Profilage : Trouver les goulots d'étranglement

La première étape de l'optimisation est le diagnostic. Go fournit le package intégré net/http/pprof pour collecter les profils CPU, mémoire, verrous et goroutines.



Démarrer le profilage

Ajoutez dans main.go :

import (    _ "net/http/pprof"    "net/http")

func main() { go func() { http.ListenAndServe("localhost:6060", nil) }() // votre code principal}

Exécutez ensuite :
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30



Analyser le profil CPU

Après avoir collecté les données, une console interactive s'ouvre. Utilisez les commandes :

  • top10 — affiche les 10 fonctions les plus "chaudes" ;
  • web — visualise le graphe d'appels dans le navigateur ;
  • list <nom_fonction> — affiche l'utilisation du CPU ligne par ligne.

Exemple de sortie :

Showing nodes accounting for 80.60s, 85.12% of 94.70s total      flat  flat%   sum%        cum   cum%    20.30s 21.44% 21.44%     20.30s 21.44%  runtime.memmove    15.10s 15.94% 37.38%     15.10s 15.94%  runtime.mallocgc

Si vous voyez runtime.memmove ou mallocgc en haut — le problème est une allocation mémoire fréquente.



2. Gestion de la mémoire et GC

Le ramasse-miettes en Go est "stop-the-world", mais depuis Go 1.5, il est devenu parallèle. Néanmoins, les allocations fréquentes augmentent la charge sur le GC.



Éviter les allocations inutiles

Mauvais exemple :

func sum(values []int) int {    total := 0    for _, v := range values {        total += v    }    // la slice est passée par référence, mais si vous créez une copie — c'est une allocation    return total}

Bon exemple — utilisez des canaux bufferisés et des pools d'objets :

var bufferPool = sync.Pool{    New: func() interface{} {        return make([]byte, 1024)    },}

func process() { buf := bufferPool.Get().([]byte) defer bufferPool.Put(buf) // travailler avec buf}


Réglage du GC

La variable d'environnement GOGC contrôle la fréquence de collecte. La valeur par défaut est 100 (la collecte démarre lorsque la taille du tas double). Augmentez-la à 200–500 pour les applications avec de nombreuses allocations :

export GOGC=200./monapp

Mais attention : un GOGC trop élevé peut entraîner une consommation mémoire de pointe.



3. Concurrence : Goroutines et Canaux

Go est réputé pour ses goroutines légères, mais une utilisation incorrecte entraîne des fuites et des interblocages.



Limiter le nombre de goroutines

Utilisez un pool de workers :

func workerPool(tâches []int, nbWorkers int) {    tâchesChan := make(chan int, len(tâches))    résultats := make(chan int, len(tâches))

for w := 0; w < nbWorkers; w++ { go func() { for tâche := range tâchesChan { résultats <- traiterTâche(tâche) // travail lourd } }() }

for _, j := range tâches { tâchesChan <- j } close(tâchesChan)

for i := 0; i < len(tâches); i++ { <-résultats }}


Éviter le blocage et les interblocages

Utilisez select avec des timeouts :

select {case res := <-résultatChan:    return rescas <-time.After(5 * time.Second):    return nil                

Blogs

Book Recommendations