lequel est plus vite? «Vecteur de struct» ou «nombre de vecteurs»?

Solution 1: Si j’ai un cours comme

class car{ public: int a; ssortingng b; bool c;}; 

Je peux construire un vecteur de 200 voitures:

 std::vector allcas; allcars.resize(200) 

au moment de l’exécution, je fais juste:

 this_car=allcars[102]; 

puis ….

Solution 2:

j’ai

 std::vector a; a.resize(200); std::vectorb; b.resize(200); std::vector c; c.resize(200); this_car_a = a[102]; this_car_b = b[102]; this_car_c = c[102]; 

Question: Lequel est le plus rapide?

est-ce que quelqu’un a une idée? Merci beaucoup d’avance!

Une “structure de vecteurs” présente quelques avantages par rapport à un “vecteur de structures”:

  • Si votre boucle interne n’utilise pas tous les éléments de la structure, la structure de vecteurs peut économiser sur la bande passante de la mémoire, car les vecteurs d’éléments inutilisés ne seront pas chargés dans le cache.
  • Il est plus facile de vectoriser. Une structure de vecteurs peut vous permettre d’utiliser les instructions de traitement vectoriel de votre processeur (via un assemblage, des composants insortingnsèques ou des compilateurs intelligents) pour accélérer vos boucles internes.

D’autre part, l’optimisation prématurée est la racine de tout mal:

  • L’utilisation d’une structure de vecteurs est plus difficile, maladroite et obscure.
  • En général, vous ne savez pas où se situent vos goulets d’étranglement tant que votre code n’est pas opérationnel. Vaut-il la peine de rendre votre code plus bavard, fragile et difficile? Vous ne saurez pas jusqu’à ce que vous le profiliez réellement.
  • Les avantages de la programmation par structure de vecteurs varient au cas par cas. Cela ne donne pas toujours une accélération; vous pourriez en fait vous retrouver avec une performance inférieure.
  • En particulier, si votre modèle d’access est aléatoire (par opposition à séquentiel ou autrement localisé), une organisation structurée de vecteurs pourrait finir par charger beaucoup plus de données inutiles en mémoire, si chaque ligne de cache contient des éléments de plusieurs objects proches …

Donc, ma recommandation est d’utiliser le vecteur de structure par défaut, mais de garder la structure de vecteur à l’esprit (c’est-à-dire, assurez-vous de pouvoir basculer plus tard, si vous attendez des modèles d’access séquentiel / local coûte beaucoup d’effort à l’avant). Une fois que votre programme est en cours d’exécution, vous pouvez le profiler pour voir où se trouvent les sections critiques en termes de performances, et essayer des opérations de struct-of-vector et vectorisées où elles feront le plus grand bien.

Si a , b et c vont ensemble et forment un object ensemble, pourquoi diable les diviseriez-vous? Optez pour la clarté et la lisibilité en premier. Tout le rest vient après ça. Aussi, je pense que la v2 serait plus lente. Plus d’access sur le vecteur. N’a pas le temps cependant. Comme toujours pour les questions sur la vitesse, chronométrez .

Les processeurs adorent le prélecture.

Si vous allez parcourir linéairement vos données selon le modèle suivant …

 abcabcacb... 

… alors vous êtes mieux (en termes de performances) avec la solution n ° 1. Si vous allez y accéder en tant que:

 aaa...bbb..ccc... 

… puis optez pour la solution n ° 2.

Cependant , si vous n’effectuez pas de parcours linéaire ou si vous n’avez pas réellement analysé votre code et conclu que vous devez réellement exploiter chaque dernière performance de ce code, maintenez votre facilité de maintenance à un avantage et restz fidèle à Solution #1.

— MODIFIER —

Dans un environnement multithread, la disposition physique des données peut entraîner un faux partage . En gros, garder trop près les éléments de données auxquels plusieurs threads ont access simultanément peut provoquer des conflits de cache et détruire l’évolutivité.

Ainsi, si vous accédez simultanément à a depuis un thread et à b depuis un autre, il peut être intéressant de les séparer physiquement et de mettre en œuvre la solution n ° 2. Si, par contre, vous accédez à deux “frères et sœurs”, respectez la solution n ° 1.

— EDIT 2 —

Pour l’excellent traitement de ce sujet, je recommande chaudement l’exposé de Herb Sutter “Ce que votre langage de programmation ne vous a jamais dit”, toujours disponible à l’adresse suivante:

http://video.google.com/videoplay?docid=-4714369049736584770 http://www.nwcpp.org/Downloads/2007/Machine_Architecture_-_NWCPP.pdf

Tout d’abord, les séparer est une idée horrible pour des raisons de maintenabilité, ce qui devrait être votre principale préoccupation.

Deuxièmement, vous venez de sortingpler votre temps d’allocation (trois allocations au lieu d’une), votre temps de désallocation (identique) et de détruire la localité de référence du cache (probablement un ralentissement).

Troisièmement, le seul avantage serait que vous lisiez un seul membre pour toutes les voitures et que vous modifiez rarement les voitures.

Cela dépend vraiment de la manière dont vous voulez utiliser vos données. Par exemple, si vous souhaitez uniquement accéder à un champ:

 car this_car = allcars[12]; cout << this_car.a; 

Cela vous oblige ensuite à créer une copie de this_car. Dans ce cas, vous copiez inutilement les champs b et c. Bien sûr, vous pouvez résoudre ce problème en obtenant par référence:

 car & this_car = allcars[12]; 

C'est potentiellement encore plus lent que de simplement faire

 a = a[12]; 

Toutefois, si vous souhaitez accéder à plusieurs propriétés de votre classe, il est certainement préférable de les stocker ensemble. À ce stade, vous obtiendrez probablement de meilleures performances en raison de la localité de référence , mais tout dépend vraiment du compilateur, du gestionnaire de mémoire, etc.

En fin de compte, la meilleure réponse est: cela dépend. Ce ne sera certainement pas une décision goulot d'étranglement, et il est certainement préférable de les conserver dans une seule structure pour la lisibilité du code / votre propre santé mentale.

Cela dépend de la taille des membres de la structure et de votre access au modèle. Un seul access n’est pas pertinent, mais considérons que vous faites une itération sur un vecteur et que vous êtes uniquement intéressé par membre a . Plus la structure est large, moins il y aura d’entrées dans une ligne de cache et plus vous manquerez de cache. Déplacer tous les membres séparés dans un vecteur augmente la densité de la ligne de cache et donc les performances. Cela peut être assez important (1,5x, 2x, encore plus).

Cependant, il est beaucoup plus important de se concentrer sur la maintenabilité du code, de le rendre lisible, débogable et facile à refactoriser. Le code doit clairement exprimer l’intention. Les micro-optimisations dont vous parlez ne devraient être sockets en compte que pour les goulots d’étranglement mesurés . Procurez-vous une copie du livre de recettes d’optimisation logicielle .