8
votes

Initialisation du vecteur plus lent que la matrice ... pourquoi?

J'ai essayé 2 choses: (pseudo code ci-dessous) xxx

et xxx

J'ai exécuté à la fois les programmes et l'a programmé en utilisant le Commande "Time" Shell. Le programme 1 fonctionne en 5 secondes, le programme 2 est exécuté en 30 secondes. J'ai exécuté les deux programmes avec optimisation du compilateur activé et les deux programmes ont couru à peu près au même moment (0,38s). Je suis confus par ces résultats. Quelqu'un peut-il vous expliquer pourquoi cela se passe-t-il?

Merci!


4 commentaires

Voulez-vous dire qu'ils ont pris 5/30 secondes avec des optimisations off ?


Gardez à l'esprit qu'ils ne sont pas exactement équivalents. Vector alloue le tas par défaut, mais le tableau est sur la pile.


Bonjour Jalf, oui, cela faisait partie de ma question. J'ai également été confondu par la manière dont ils ont exécuté à la fois après l'optimisation.


Merci pour vos réponses à tous. C'est une grande communauté! Je ne peux pas croire à quelle vitesse ma question a répondu :)


6 Réponses :


16
votes

Pour le modèle, l'inscription est effectuée avec l'opérateur []. Avec l'optimisation éteinte, cela sera généralement généré comme un appel de fonction réel, ajoutant beaucoup de frais généraux à quelque chose de simple que sous-dominant dans un tableau. Lorsque vous activez l'optimisation, il est généré en ligne, en supprimant cette surcharge.


5 commentaires

Hey Jerry, merci de votre réponse. Cela a du sens maintenant. Je suppose que avec des tableaux, en utilisant [] n'appelle pas l'appel à l'opérateur [] puisqu'un «naturel» (pour un manque de meilleur mot). D'où le 5/30.


Droite - Pour un tableau intégré, le code d'inscription est presque certainement toujours généré en ligne.


Et cela souligne la manière dont les frais de fonction peuvent vraiment s'additionner.


@ AIP.CD.AISH: Les mots "intrinsèques" et "natifs" sont utilisés plus couramment que "naturel" pour décrire les caractéristiques intégrées dans une langue.


@Adisak: Cool, merci. Bon à savoir :)



8
votes

En mode de débogage, implémentations de std :: vecteur fournit beaucoup de vérification de la facilité d'utilisation. Cette vérification n'est pas disponible pour les tableaux natifs. Par exemple, dans VC2008, si vous compilez votre exemple de vecteur dans le mode de débogage, il y aura la vérification de la plage même dans le cas du opérateur [] .


0 commentaires

5
votes

Si votre implémentation vectorielle non optimisée effectue une vérification des limites, cela expliquerait la divergence.


1 commentaires

++ Mon hypothèse est que vous avez raison, mais je le voulais (ou elle) de le découvrir.



0
votes

parce que lorsque vous écrivez vectoriel Arr (10000); Vous créez un objet, appelez ses fonctions ... quand et il sera plus lent que vous créez INTRA [10000];


0 commentaires

0
votes

Dans vos exemples, le tableau est sur la pile. L'accès aux données dans le tableau consiste à accéder aux données sur la pile. C'est vite.

D'autre part, tandis que le vecteur est sur la pile, les données d'un std :: vecteur est allouée ailleurs (par défaut, il est attribué Sur le tas via std :: allocator ). L'accès à des données dans le vecteur implique d'accéder aux données sur le tas. C'est beaucoup plus lent que d'accéder à des données sur la pile.

Vous obtenez quelque chose pour la pénalité de performance, cependant. std :: vecteur est griffable, tandis qu'une matrice régulière n'est pas. De plus, la taille d'un std :: vecteur ne doit pas nécessairement compiler la constante de temps, tandis que la taille d'un tableau sur la pile est. Un tableau alloué en tas (via opérateur nouveau [] ) ne doit pas nécessairement être une constante de la compilation. Si vous comparez un tableau alloué en tas avec un std :: vecteur Vous trouverez que la performance est beaucoup plus proche. xxx


0 commentaires

4
votes

Ce sont de bonnes réponses, mais il y a un moyen rapide que vous puissiez découvrir pour vous-même.

Vous voyez une différence de performance de 6 à 1? Il suffit d'exécuter le lent et appuyez sur le bouton "Pause". Ensuite, regardez la pile d'appels. La probabilité est de 5 sur 6 (83%) que vous verrez exactement comment il dépense ces 25 secondes supplémentaires. Faites-le plusieurs fois pour obtenir autant d'idées que vous le souhaitez.

Pour le cas optimisé, faites de même avec le programme 1. Étant donné qu'il est 13 fois plus lent que le programme optimisé, vous verrez la raison pour laquelle sur chaque "pause", avec probabilité 12/13 = 92%.

C'est une application de cette technique .


9 commentaires

J'ai vu de nombreux développeurs qui a soufflé lors de la première vue sur la bonne technique de pause Ole ', surtout quand ils ne l'achètent pas et dépenseront une autre heure serveur de régler une course de profilage complet uniquement pour découvrir "pause" l'avaient déjà cloué.


@Dano: Ouais. J'essaie juste d'obtenir le mot. Il n'y a aucune raison pour que les gens ne le connaissent pas.


Hey Mike, merci pour la réponse. J'aimerais essayer, mais j'utilise un environnement de ligne de commande et GCC pour compiler mes programmes (je suis nouveau dans cet environnement). Y a-t-il de ce que je peux la mettre en pause et voir la trace de la pile là-bas? Merci :)


@ AIP.CD.AISH: J'aimerais que ce soit facile. Fondamentalement, vous devez être utile avec GDB. Ensuite, configurez-la de sorte que le contrôle-c secrété l'interrompt, mais ne l'abandonne pas. Franchement, sous une boîte DOS dans Windows XP, je n'ai pas réussi, si surtout j'utilise VC & vs. Sous UNIX, j'avais l'habitude d'utiliser ADB et je l'envoie un signal de tuer de l'extérieur. J'ai demandé si s'il y a une meilleure façon, mais pas vraiment une bonne réponse.


... Il y a une façon maladroite que j'ai parfois utilisé. Écrivez une fonction vide FOO () {} et saupoudrez des appels sur tout le code. Mettez un point d'arrêt dedans et désactivez cela. Ensuite, quand il fonctionne, voyez si vous pouvez activer le point d'arrêt à un moment aléatoire. Cette méthode n'est pas aussi précise, mais mieux que rien.


... Il y a une autre façon qui pourrait fonctionner dans votre cas. Dans GDB, une seule étape au niveau de l'instruction "SI". Vous verrez exactement ce que ça fait (bien que vous ne l'aimez peut-être pas :).


@Dano: On me rappelle une histoire d'Edison, où il interviewait des ingénieurs. Il leur a demandé de trouver le volume d'un globe d'ampoule. La plupart d'entre eux se sont fixés pour travailler avec calcul et géométrie. On vient de le remplir d'eau et versé dans une tasse à mesurer!


@ AIP.CD.AISH: Utilisez Explorateur de processus de Sysinternals / TechNet, sur la page Process Propriétés | Tabure de threads, choisissez un fil et appuyez sur le bouton de la pile. Vous recevez un instantané lorsque vous avez poussé le bouton. Regardez ce qui est sur le dessus de la fermeture et la remontant à nouveau, vous pouvez facilement obtenir un nouvel échantillon presque chaque seconde. Bien sûr sans mettre en place des symboles, vous obtenez uniquement des compensations. Mais vous pouvez également voir dans les DLL du système de cette façon.


@Dano: Je n'étais pas au courant de l'explorateur de processus, merci. C'est bien que vous puissiez voir dans des dlls système, mais ce que je cherche, c'est des appels de pile mi-pile en code que j'ai le contrôle. Exemple: Stackoverflow.com/ Questions / 406760 / ...