Bonjour les Gophers ?
Dans cet article de blog, je vais vous montrer comment utiliser un outil génial intégré au package de test #golang. Comment testeriez-vous les performances d’un morceau de code ou d’une fonction ? Utilisez des tests de référence.
Allons-y.
Pour ce test, j'utiliserai le nombre de Fibonacci classique ou la séquence de Fibonacci, qui est déterminé par :
if (x < 2) F(0) = 1 F(2) = 2 else F(x) = F(x-1) + F(x-2) In practice, the sequence is: 1, 1, 2, 3, 5, 8, 13, etc.
Cette séquence est importante car elle apparaît également dans plusieurs parties des mathématiques et de la nature, comme indiqué ci-dessous :
Il existe plusieurs façons d'implémenter ce code, et j'en choisirai deux pour nos tests de référence : les méthodes récursives et itératives de calcul. L'objectif principal des fonctions est de fournir une position et de renvoyer le nombre de Fibonacci à cette position.
// main.go func fibRecursive(n int) int { if n <= 2 { return 1 } return fibRecursive(n-1) + fibRecursive(n-2) }
// main.go func fibIterative(position uint) uint { slc := make([]uint, position) slc[0] = 1 slc[1] = 1 if position <= 2 { return 1 } var result, i uint for i = 2; i < position; i++ { result = slc[i-1] + slc[i-2] slc[i] = result } return result }
Ces méthodes ne sont pas optimisées, mais les résultats des tests sont sensiblement différents même pour un petit nombre. Vous le verrez dans les tests. Pour suivre le code, vous pouvez cliquer ici.
Maintenant, pour les tests benchmark, écrivons quelques tests dans le fichier _main_test.go. En utilisant la documentation de Golang sur benchmark, vous pouvez créer les fonctions à tester comme suit :
// main_test.go // The key is to start every function you want to benchmark with the keyword Benchmark and use b *testing.B instead of t *testing.T as input func BenchmarkFibIterative(b *testing.B) { // Use this for-loop to ensure the code will behave correctly. // Now, you can put the function or piece of code you want to test for i := 0; i < b.N; i++ { fibIterative(uint(100)) } } // Same as above func BenchmarkFibRecursive(b *testing.B) { for i := 0; i < b.N; i++ { fibRecursive(100) } }
Question, avant de continuer : lequel est le plus rapide ?
Faisons le test pour un petit nombre (10) et pour un nombre légèrement plus grand (80). Pour exécuter les tests benchmark, il vous suffit d'exécuter la commande :
aller tester -bench=NomdelaFonction
Si vous souhaitez en savoir plus sur cette commande, cliquez ici.
Premier test : position=10
//(fibIterative) Results: cpu: Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz BenchmarkFibIterative-8 24491042 42.50 ns/op PASS ok playground 1.651s
Analysons à l'aide de cette image :
Selon l'image, nous avons 8 cœurs pour les tests, sans limite de temps (il fonctionnera jusqu'à la fin). Il a fallu 1,651s pour terminer la tâche.
==== Extra ==== We got 24,491,042 iterations (computations), and each iteration (op) took 42.50 ns. Doing some math, we can calculate how much time one op took: 42.50 ns/op with 1 ns = 1/1,000,000,000 s op ≈ 2.35270590588e-12 s ==== Extra ====
C’est un bon résultat. Vérifions la fonction récursive pour la position 10 :
// Results BenchmarkFibRecursive-8 6035011 187.8 ns/op PASS ok playground 1.882s
Nous pouvons voir qu'il a fallu 1,882s pour terminer la tâche.
La fonction itérative a gagné de quelques décisecondes. Essayons encore un test avec :
Position 50
// Results for the Iterative Function cpu: Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz BenchmarkFibIterative-8 27896118 45.37 ns/op PASS ok playground 2.876s // Results for the Recursive Function cpu: Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz BenchmarkFibRecursive-8 6365198 186.3 ns/op PASS ok playground 1.918s
Wow ! Maintenant, la fonction récursive est plus rapide ?
Terminons avec un nombre légèrement plus grand.
Position 80
// Results for the Iterative Function cpu: Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz BenchmarkFibIterative-8 5102344 229.5 ns/op PASS ok playground 1.933s // Results for the Recursive Function // My poor PC couldn’t handle it, so I had to reduce the position to 50 just to get some results printed. cpu: Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz BenchmarkFibRecursive-8 1 44319299474 ns/op PASS ok playground 44.951s
La différence est énorme. Pour la position 80, l'approche itérative a duré environ 2 secondes. Pour la position 50, la fonction récursive a pris environ 45 secondes. Cela démontre l'importance de comparer votre code lorsque votre projet Golang commence à ralentir.
Si votre code de production s'exécute lentement ou est plus lent de manière imprévisible, vous pouvez utiliser cette technique, combinée avec pprof ou d'autres outils du package de test intégré, pour identifier et tester les performances de votre code. mal et comment l'optimiser.
Remarque : tous les codes qui sont beaux à regarder ne sont pas plus performants.
Pouvez-vous trouver une meilleure façon d'améliorer la fonction récursive ? (Conseil : utilisez la programmation dynamique). Cet article explique pourquoi pour certains petits nombres, la stratégie récursive est meilleure.
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!