Dans ce microbenchmark d'accès aux baies (par rapport à GCC), Go subit une perte de performances 4x. Qu'est-ce qui cause cela ? Ce problème implique de nombreux aspects tels que le mécanisme d'exécution et l'optimisation du compilateur du langage Go. Tout d'abord, le langage Go utilise un mécanisme de vérification des limites lors de l'accès aux tableaux, c'est-à-dire que des vérifications des limites sont effectuées à chaque accès à un élément du tableau, ce qui entraînera une certaine perte de performances. Deuxièmement, le compilateur du langage Go est relativement faible en termes d'optimisation et ne peut pas bien optimiser l'accès aux tableaux. De plus, le mécanisme de garbage collection du langage Go aura également un certain impact sur les performances. Pris ensemble, ces facteurs se sont combinés pour que Go subisse une perte de performances 4x dans le microbenchmark d’accès aux baies.
J'ai écrit ce microbenchmark pour mieux comprendre les caractéristiques de performance de Go afin de pouvoir faire des choix éclairés quant au moment de l'utiliser.
Du point de vue des performances, je pense que ce serait un scénario idéal pour aller :
Néanmoins, j'ai constaté une différence de vitesse 4x par rapport à gcc -o3
sur amd64. pourquoi donc?
(Utilisez le timing du shell. Cela prend quelques secondes à chaque fois, le démarrage est donc négligeable)
package main import "fmt" func main() { fmt.println("started"); var n int32 = 1024 * 32 a := make([]int32, n, n) b := make([]int32, n, n) var it, i, j int32 for i = 0; i < n; i++ { a[i] = i b[i] = -i } var r int32 = 10 var sum int32 = 0 for it = 0; it < r; it++ { for i = 0; i < n; i++ { for j = 0; j < n; j++ { sum += (a[i] + b[j]) * (it + 1) } } } fmt.printf("n = %d, r = %d, sum = %d\n", n, r, sum) }
Version c :
#include <stdio.h> #include <stdlib.h> int main() { printf("started\n"); int32_t n = 1024 * 32; int32_t* a = malloc(sizeof(int32_t) * n); int32_t* b = malloc(sizeof(int32_t) * n); for(int32_t i = 0; i < n; ++i) { a[i] = i; b[i] = -i; } int32_t r = 10; int32_t sum = 0; for(int32_t it = 0; it < r; ++it) { for(int32_t i = 0; i < n; ++i) { for(int32_t j = 0; j < n; ++j) { sum += (a[i] + b[j]) * (it + 1); } } } printf("n = %d, r = %d, sum = %d\n", n, r, sum); free(a); free(b); }
Mise à jour :
range
peut augmenter la vitesse de déplacement de 2 fois. -march=native
将 c 速度提高了 2 倍。 (并且-mno-sse
给出编译错误,显然与-o3
n'est pas compatible)range
) Regardez la sortie assembleur du programme C et du programme Go. Au moins sur les versions Go et GCC que j'ai utilisées (respectivement 1.19.6 et 12.2.0), la différence la plus directe et la plus évidente est que GCC. Vectoriser automatiquement les programmes C, ce que le compilateur Go semble incapable de faire.
Cela explique également pourquoi vous constateriez une quadruple augmentation des performances, puisque GCC utilise SSE au lieu d'AVX lorsqu'il ne cible pas une architecture spécifique, ce qui signifie que les instructions scalaires 32 bits sont quatre fois plus larges sur lesquelles fonctionner. En fait, l'ajout de -march=native
m'a permis d'améliorer les performances de 2 fois car GCC a généré du code AVX sur mon processeur.
Je ne connais pas assez Go pour vous dire si le compilateur Go est intrinsèquement incapable de vectoriser automatiquement, ou si c'est juste ce programme particulier qui le provoque pour une raison quelconque, mais cela semble être la cause première
.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!