Profilage du code Go : trouver les goulots d'étranglement pour les débutants
\n\nLorsque votre projet Go commence à ralentir, à consommer trop de mémoire ou à fonctionner de manière instable, une question légitime se pose : "Où se trouve le goulot d'étranglement ?" Les suppositions intuitives aident rarement — il faut des données précises. Le profilage (profiling) est le processus de collecte de métriques sur le fonctionnement d'un programme : combien de temps chaque fonction prend, combien de mémoire est allouée, à quelle fréquence le ramasse-miettes est appelé. Dans cet article, nous allons voir comment, à l'aide des outils intégrés de Go (pprof et trace), trouver et résoudre rapidement les problèmes de performance.
\n\nQu'est-ce que le profilage et pourquoi en a-t-on besoin ?
\n\nLe profilage, c'est comme une radiographie de votre code. Vous ne voyez pas simplement "le programme fonctionne lentement", mais des chiffres concrets : la fonction parseData() prend 40% du temps, et loadConfig() alloue 2 Go de mémoire. Pour Go, il existe plusieurs types de profils :
- \n
- Profil CPU — montre quelles fonctions consomment du temps processeur. \n
- Profil mémoire (heap) — montre quelles fonctions allouent de la mémoire et où vivent les objets. \n
- Profil Goroutine — montre le nombre de goroutines actives et leur état.
- Profil Block — montre où les goroutines sont bloquées sur des mutex ou des canaux.
- Profil Mutex — montre la concurrence pour les mutex.
Pour les débutants, le profilage CPU et mémoire est le plus utile. Ils fournissent 80% des réponses à la question "pourquoi le code ralentit".
\n\nL'outil pprof : le profileur intégré de Go
\n\nGo est livré avec le package intégré net/http/pprof. Il ajoute des points de terminaison à votre serveur HTTP à partir desquels vous pouvez capturer des profils. Regardons un exemple de base.
Étape 1 : Intégrer pprof à l'application
\n\npackage main\n\nimport (\n "fmt"\n "log"\n "net/http"\n _ "net/http/pprof" // intègre le profileur\n "time"\n)\n\nfunc main() {\n // Démarre le serveur sur le port 8080\n go func() {\n log.Println(http.ListenAndServe("localhost:8080", nil))\n }()\n\n // Notre logique métier "lourde"\n for i := 0; i < 100; i++ {\n go heavyTask(i)\n }\n\n // Attend la fin\n time.Sleep(10 * time.Second)\n fmt.Println("Done")\n}\n\nfunc heavyTask(id int) {\n // Simulation d'un travail lourd\n for i := 0; i < 1000000; i++ {\n _ = i * i\n }\n fmt.Printf("Task %d finished\\n", id)\n}\n\n\nAprès avoir lancé l'application, ouvrez le navigateur à l'adresse http://localhost:8080/debug/pprof/. Vous verrez une interface web avec des liens vers les profils.
Étape 2 : Capturer un profil CPU
\n\nLa méthode la plus simple consiste à utiliser la ligne de commande. Exécutez :
\n\ngo tool pprof http://localhost:8080/debug/pprof/profile?seconds=30\n\nCette commande collectera un profil CPU pendant 30 secondes. Une fois terminée, la console interactive pprof s'ouvrira. Tapez top pour voir les fonctions les plus "chaudes" :
(pprof) top\nShowing nodes accounting for 1.50s, 100% of 1.50s total\n flat flat% sum% cum cum%\n 1.50s 100% 100% 1.50s 100% main.heavyTask\n 0 0% 100% 1.50s 100% runtime.main\n\n\nIci, flat est le temps passé directement à l'intérieur de la fonction, et cum est le temps incluant les appels aux fonctions enfants. Dans notre exemple, 100% du temps est consacré à heavyTask.
Étape 3 : Visualisation via l'interface web
\n\nPour une analyse plus visuelle, utilisez le mode graphique :
\n\ngo tool pprof -http=:8081 http://localhost:8080/debug/pprof/profile?seconds=30\n\nUn navigateur s'ouvrira avec un graphe d'appels interactif. Plus le bloc est grand et rouge, plus il consomme de ressources. C'est un excellent moyen de trouver rapidement les fonctions "gourmandes".
\n\n