J'ai donc modifié l'implémentation de ma classe dérivant de filterIterator
:
...
class keyAsStringFilterIterator extends FilterIterator
{
protected $stringFound = true;
public function __construct(array $array)
{
asort($array);
parent::__construct(new arrayIterator($array));
}
public function rewind()
{
parent::rewind();
$this->stringFound = true;
}
public function valid()
{
return ($this->stringFound === true && parent::valid() === true);
}
public function accept()
{
if (is_string($this->key()) === false)
{
$this->stringFound = false;
}
return $this->stringFound;
}
}
...
Les plus attentifs auront remarqué que les closures
ne sont plus utilisées, puisque l'itérateur est maintenant très fortement spécialisé, d’où son changement de nom.
Afin de ne pas pénaliser l'approche traditionnelle
, j'ai également modifié son code de la manière suivante :
...
asort($array);
foreach ($array as $key => $value)
{
if (is_string($key) === true)
{
echo $value;
}
else
{
break;
}
}
...
Et les résultats, alors ?
Et bien j'aurais mieux fait d'essayer de dormir plutôt que de réfléchir à ce problème :
fch@diablo:~/tmp
37> php -nf bench.php
Iterator: abcdefghijklmnopqrstuvwxyz [0.64576697349548]
Foreach: abcdefghijklmnopqrstuvwxyz [0.26274108886719]
Delta: 0.3830258846283
Ratio: 2.4578073276613
L'itérateur reste plus de deux fois plus lent que la solution classique.
Vous me direz que c'est toujours mieux que d'être 7 fois plus lent et vous n'aurez pas tort.
Et comme quoi il n'est pas inutile d'essayer d'optimiser ses algorithmes, même si ca ne change pas la face du monde, cela permet de gagner de précieuse seconde.
Et curieusement, en chargeant mes extensions, le delta n'est plus deux fois mais bien huit fois plus important :
fch@diablo:~/tmp
40> php -f bench.php
Iterator: abcdefghijklmnopqrstuvwxyz [2.0768599510193]
Foreach: abcdefghijklmnopqrstuvwxyz [0.24072194099426]
Delta: 1.836138010025
Ratio: 8.6276304621056
Du coup, j'ai cette fois pris la peine d'investiguer, et l'extension xdebug est bien la responsable de ce phénomène puisqu'en la désactivant, je retrouve des résultats beaucoup plus similaires à ceux que j’obtiens avec les extensions désactivées.
Pour ceux qui veulent s'amuser, le code source complet est attaché à ce billet, et les tests ont été effectués dans les même conditions que dans le cadre de mon précédent billet.
Et cela n'a rien à voir avec ce qui précède, mais avec la publication de celui-ci, ce blog compte plus de 100 billets au compteur.
3 réactions
1 De metagoto - 09/04/2010, 15:30
Tu as un nouveau favicon ?
Il faut utiliser ksort() plutot que asort(). Hier j'ai parlé de asort, mais je me suis gouré, c'est bien ksort qui trie par rapport aux keys. Ca change rien pour le array source utilisé (car les keys et values sont identiques, en tout cas pour les strings), mais c'est un cas exceptionnel!
Avec juste iterator_apply sur un standard ArrayIterator + lambda, j'avais un ratio de moins de 2, toujours en faveur du foreach si celui-ci contient un break.
Et là je me demande: et si tu essayais avec des goto ?
2 De mageekguy - 09/04/2010, 15:40
@metagoto : Faut pas pousser pépére dans les orties, quand même, ca ne se fait pas. Osez proposer
cette merde degoto
! Je sais que j'en ai utilisé à la pelle dans le bon vieux temps du basic applesoft, mais t'as tout de même intérêt à faire pénitence.Et pour
ksort()
, ca a été mon premier réflexe mais ca ne marche pas, et je n'ai pas pris le temps d'en chercher la raison.Et je n'ai pas un nouveau favicon, j'ai un favicon que je n'avais pas avant ;).
J'en avais marre de voir une 404 à cause de lui dans mes statistiques.
3 De metagoto - 09/04/2010, 17:45
Tu as raison, ksort déconne. L'index 0 (la key numérique 0) fausse les comparaisons. Je me suis doublement gouré dans mon code de test car j'ai laissé trainer un asort après le ksort...
Solution: uksort! Mais là, inutile de dire que ça ne sert plus à rien de pré-trier coté php
Delta: -0.0018980503082275 Ratio: 0.94888636349044 en faveur du goto.
http://codepad.org/jKv9rDmc
C'est ridicule, je sais...