43 votes

La micro-optimisation vaut-elle le coup?

Je suis un développeur PHP et j'ai toujours pensé que les micro-optimisations ne valent pas le temps. Si vous avez vraiment besoin de cette performance, vous écrivez votre logiciel de sorte qu'il est architecturalement plus vite, ou vous écrivez une extension C++ pour gérer lente des tâches (ou, mieux encore, de compiler le code à l'aide de hip-hop). Cependant, aujourd'hui, un travail pote m'a dit qu'il y a une grande différence dans

is_array($array)

et

$array === (array) $array

et j'étais comme, "eh, c'est un non sens en comparaison vraiment", mais il ne serait pas d'accord avec moi.. et il est le meilleur développeur dans notre société et c'est la prise en charge d'un site web qui n'environ 50 millions de requêtes SQL par jour, par exemple. Donc, je me demande ici, c'est que pourrait-il être mauvais ou micro-optimisation vaut vraiment la peine de le temps et quand?

140voto

ircmaxell Points 74865

Eh bien, pour un infiniment petit tableau, $array === (array) $array est nettement plus rapide que is_array($array). Sur l'ordre de plus de 7 fois plus rapide. Mais chaque appel est seulement de l'ordre de 1.0 x 10 ^ -6 secondes (0.000001 seconds). Donc, à moins que vous appelez ça des milliers de fois, il ne va pas être la peine. Et si vous appelez ça des milliers de fois, je suggérerais que vous êtes en train de faire quelque chose de mal...

La différence vient quand vous avez affaire avec un grand tableau. Depuis $array === (array) $array nécessite une nouvelle variable à être copié exige le tableau à parcourir en interne pour la comparaison, il sera probablement beaucoup plus lent pour un grand tableau. Par exemple, sur un tableau de 100 éléments entiers, is_array($array) est à l'intérieur d'une marge d'erreur (< 2%) de l' is_array() avec un petit tableau (en 0.0909 secondes pour 10 000 itérations). Mais $array = (array) $array est extrêmement lent. Pour seulement 100 éléments, c'est déjà plus de deux fois plus lent qu' is_array() (en 0.203 secondes). Pour les éléments de 1000, is_array est restée la même, mais le casting de comparaison a augmenté de 2.0699 secondes...

La raison c'est plus rapide pour les petites matrices est qu' is_array() a la surcharge d'être un appel de fonction, où l'opération de cast est une simple construction du langage... Et de parcourir un petit variable (dans le code C) sera généralement moins cher que l'appel de la fonction de surcharge. Mais, pour les grandes variables, l'écart grandit...

C'est un compromis. Si le tableau est assez petit, l'itération sera plus efficace. Mais comme la taille de la matrice augmente, il devient de plus en plus lent (et donc l'appel de la fonction devient plus rapide).

Une Autre Façon De Voir Les Choses

Une autre façon de voir les choses serait d'examiner la complexité algorithmique de chaque fonte.

Jetons un coup d'oeil à l' is_array() première. C'est le code source montre fondamentalement c'est un O(1) de l'opération. C'est une constante de temps de l'opération. Mais nous avons aussi besoin de regarder à l'appel de la fonction. En PHP, les appels de fonction avec un seul paramètre de type tableau sont soit O(1) ou O(n) selon si la copie sur écriture doit être déclenchée. Si vous appelez is_array($array) lorsque $array est une variable de référence, de copie sur écriture sera déclenchée et une copie de la variable qui va se produire.

Donc, par conséquent, is_array() est un meilleur des cas O(1) et le pire-cas O(n). Mais tant que vous n'êtes pas à l'aide de références, c'est toujours O(1)...

Le casting de la version, d'autre part, n'deux opérations. Il fait un jeté, puis il effectue un contrôle d'égalité. Jetons un oeil à chacune d'elles séparément. L'opérateur de cast gestionnaire oblige dans un premier temps une copie de la variable d'entrée. Peu importe si c'est une référence ou pas. Donc tout simplement à l'aide de l' (array) opérateur de coulée forces de l' O(n) itération sur le tableau de le jeter (via le copy_ctor appel).

Ensuite, il convertit la nouvelle copie d'un tableau. C'est - O(1) pour les tableaux et les primitives, mais O(n) pour les objets.

Puis, à l'identique de l'opérateur exécute. Le gestionnaire est juste un proxy à l' is_identical_function(). Maintenant, is_identical court-circuit si $array n'est pas un tableau. Par conséquent, il a un meilleur des cas, d' O(1). Mais si $array est un tableau, il peut court-circuit à nouveau si les tables de hachage sont identiques (ce qui signifie les deux variables sont de copie sur écriture des copies les uns des autres). Donc, ce cas est - O(1) ainsi. Mais n'oubliez pas que nous avons forcé un exemplaire ci-dessus, nous ne pouvons pas le faire si c'est un tableau. Il est donc O(n) grâce à zend_hash_compare...

De sorte que le résultat final est ce tableau de pire cas d'exécution:

+----------+-------+-----------+-----------+---------------+
|          | array | array+ref | non-array | non-array+ref |
+----------+-------+-----------+-----------+---------------+
| is_array |  O(1) |    O(n)   |    O(1)   |     O(n)      |
+----------+-------+-----------+-----------+---------------+
| (array)  |  O(n) |    O(n)   |    O(n)   |     O(n)      |
+----------+-------+-----------+-----------+---------------+

Notez qu'il ressemble à plus grande échelle le même pour les références. Ils n'en ont pas. Ils ont tous deux l'échelle linéaire pour les variables référencées. Mais le facteur constant changement. Par exemple, dans un référencés tableau de taille 5, is_array effectuera 5 allocations de mémoire, et 5 de la mémoire des copies, suivi par 1 vérification de type. Le casting de la version, d'autre part, effectuera 5 allocations de mémoire, 5 mémoire des copies, suivi par 2 type de contrôles, suivi de 5 type de contrôles et 5 contrôles d'égalité (memcmp() ou similaire). Donc, n=5 rendements 11 ops is_array, encore 22 ops ===(array)...

Maintenant, is_array() ne O(1) les frais généraux d'une pile push (en raison de l'appel de la fonction), mais qui ne feront qu'dominer runtime pour de très petites valeurs de n (nous l'avons vu dans la référence ci-dessus à seulement 10 éléments d'un tableau a été suffisant pour éliminer complètement toute la différence).

La Ligne De Fond

Je vous conseille d'aller pour des raisons de lisibilité si. - Je trouver de l' is_array($array) à être beaucoup plus lisible qu' $array === (array) $array. Ainsi, vous obtenez le meilleur des deux mondes.

Le script que j'ai utilisé pour le test:

$elements = 1000;
$iterations = 10000;

$array = array();
for ($i = 0; $i < $elements; $i++) $array[] = $i;

$s = microtime(true);
for ($i = 0; $i < $iterations; $i++) is_array($array);
$e = microtime(true);
echo "is_array completed in " . ($e - $s) ." Seconds\n";

$s = microtime(true);
for ($i = 0; $i < $iterations; $i++) $array === (array) $array;
$e = microtime(true);
echo "Cast completed in " . ($e - $s) ." Seconds\n";

Edit: Pour l'enregistrement, ces résultats ont été avec 5.3.2 sur Linux...

Edit2: Fixe la raison pour laquelle le tableau est plus lent (c'est en raison de l'itération en comparaison à la place de la mémoire raisons). Voir compare_function pour l'itération code...

89voto

Jon Skeet Points 692016

Micro-optimisation de la peine quand vous avez la preuve que vous êtes l'optimisation d'un goulot d'étranglement.

Habituellement, il n'est pas la peine écriture la plus lisible le code vous pouvez, et utilisez des repères afin de vérifier la performance. Si et quand vous trouvez que vous avez un goulot d'étranglement, micro-optimiser juste ce bout de code (de mesure que vous allez). Parfois, une petite quantité de micro-optimisation peut faire une énorme différence.

Mais ne pas micro-optimiser tout votre code... il va finir par être beaucoup plus difficile à maintenir, et vous aurez très probablement trouver que vous avez raté le véritable goulot d'étranglement, ou que votre micro-optimisations sont de nuire à la performance au lieu de les aider.

12voto

Mike Dunlavey Points 25419

Est la micro-optimisation du temps?

Non, à moins qu'il est.

En d'autres termes, a priori, la réponse est "non", mais après vous connaissez une ligne de code spécifique consomme une bonne santé pour cent de temps de l'horloge, alors, et seulement alors, il vaut la peine de l'optimisation.

En d'autres termes, le profil d'abord, parce que sinon, vous n'avez pas de connaissances. C'est la méthode que je appuyer sur, indépendamment de la langue ou de l'OS.

Ajouté: Lorsque de nombreux programmeurs de discuter de la performance, des experts, ils ont tendance à parler de "où" le programme passe son temps. Il y a une astuce ambiguïté dans l' "où" qui les conduit à l'écart de ce qui pourrait sauver le plus de temps, à savoir, l'appel de la fonction des sites. Après tout, "l'appel Principal" au sommet d'une application est un "lieu" que le programme est presque jamais "à", mais est responsable de 100% du temps. Maintenant, vous n'allez pas vous débarrasser de "l'appel Principal", mais il y a presque toujours d'autres appels que vous pouvez vous débarrasser de. Alors que le programme est en cours d'ouverture ou de fermeture d'un fichier, ou de mise en forme des données dans une ligne de texte, ou de l'attente pour une connexion de socket, ou "nouveau"-ing une partie de la mémoire, ou de passer une notification au sein d'une grande structure de données, c'est passer beaucoup de temps dans les appels de fonctions, mais est-ce que "où il est? De toute façon, ces appels sont rapidement trouvé avec pile d'échantillons.

6voto

dsimcha Points 32831

Comme le cliché va, les micro-optimisation est généralement vaut le temps que dans la plus petite, la plupart des critiques des performances hotspots de votre code, et seulement après que vous avez éprouvée , d'où le goulet d'étranglement. Cependant, je tiens à chair ce un peu, à quelques exceptions et des zones d'incompréhension.

  1. Cela ne signifie pas que la performance ne devrait pas être considéré à tous d'avance. Je définis la micro-optimisation des optimisations basées sur les détails de bas niveau de l'compilateur/interpréteur, le matériel, etc. Par définition, un micro-optimisation n'affecte pas le big-O de la complexité. Macro-optimisations doivent être considérés d'emblée, surtout quand ils ont un impact majeur sur la conception de haut niveau. Par exemple, il est assez sûr de dire que si vous avez un grand, données fréquemment consultées structure, un O(N) la recherche linéaire ne va pas le couper. Même les choses qui ne sont que des termes constants, mais ont une grande et évidente de la surcharge pourrait être intéressant d'envisager à l'avance. Deux grands exemples sont excessives d'allocation de mémoire/de copie de données et de calcul deux fois la même chose quand vous pourriez être l'informatique en une fois et le stockage de réutiliser le résultat.

  2. Si vous êtes en train de faire quelque chose qui a été fait avant dans un contexte légèrement différent, il peut y avoir certains goulots d'étranglement qui sont si bien connus qu'il est raisonnable de les examiner à l'avance. Par exemple, j'ai récemment été de travailler sur la mise en œuvre de la FFT (fast Fourier Transform) algorithme pour la D de la bibliothèque standard. Comme beaucoup de Fft ont été écrits dans d'autres langues, il est très bien connu que le principal goulet d'étranglement des performances du cache, je suis donc allé dans le projet immédiatement penser à comment optimiser ce.

3voto

James Curran Points 55356

Eh bien, je vais supposer que is_array($array) est la manière préférée, et $array === (array) $array est apparemment la plus rapide (qui se poser la question pourquoi n'est-ce pas is_array mis en œuvre à l'aide de cette comparaison, mais je m'égare).

Je vais presque jamais de retourner dans mon code et insérez un micro-optimisation*, mais je vais souvent mettre dans le code comme je l'écris, à condition:

  • il ne ralentit pas mon de frappe vers le bas.
  • le but du code est encore clair.

Cette optimisation échoue sur les deux plans.


* OK, en fait je ne, mais qui a plus à voir avec moi, d'avoir une touche de trouble obsessionnel-compulsif plutôt que les bonnes pratiques de développement.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X