Pourquoi est la file d'attente.sondage plus rapide que l'Itération? (Java.util.simultané.ConcurrentLinkedQueue)


J'ai un morceau de code qui obtient tous les éléments d'une file d'attente. Je ne me soucie pas de l'état de la file d'attente par la suite et je peux être assuré que la file d'attente ne sera pas modifiée pendant que j'en retire les éléments.

J'utilisais initialement un itérateur pour extraire les éléments parce que je pensais que ce serait plus rapide que d'interroger les éléments...

Mais j'ai exécuté le test suivant:

ConcurrentLinkedQueue<Object> queue = new ConcurrentLinkedQueue<>();
for (int i=0; i < 1000000; i++)
    queue.add(new Object());

LinkedList<Object> list = new LinkedList<>();
long start = System.currentTimeMillis();
for (Object object: queue)
    list.add(object);
long time1 = System.currentTimeMillis() - start;

list = new LinkedList<>(); 
start = System.currentTimeMillis();
Object object;
while ((object = queue.poll()) != null)
    list.add(object);
long time2 = System.currentTimeMillis() - start;

System.out.println(time1 + " " + time2);

J'ai obtenu la sortie suivante (moyenne sur 100 exécutions)

1169 46

Ma question est: Pourquoi poll est-il plus rapide que itérer? C'est complètement peu intuitif pour moi car poll devra modifier la file d'attente et itérer n'aura qu'à regarder l'état.

Edit --- Gray avait raison

Je l'ai exécuté en boucle et j'ai obtenu la sortie (j'aurais dû le faire en premier lieu)

1180 46
1422 25
287 32
14 26
226 26
236 25
12 26
14 25
13 25
13 26
13 25
268 25
13 25
14 176
13 26
13 26
13 25
13 25
13 26
13 24
13 26
13 25
...
Author: nikdeapen, 2013-09-20

1 answers

Ma question est: Pourquoi le sondage est-il plus rapide que l'itération? C'est complètement peu intuitif pour moi car poll devra modifier la file d'attente et itérer n'aura qu'à regarder l'état.

Cela semble être, comme le souligne @csoroiu, un problème de compilateur hotspot. Étant donné le fonctionnement de Java, il est très important que vous "réchauffiez" votre application avant de commencer à faire des appels de synchronisation comme celui-ci.

Si j'exécute vos tests 100 fois dans une méthode que j'ai initialement vue très différente performances dues à la surcharge GC et à d'autres magies JVM. Cependant, après avoir ajouté quelques .clear() méthodes et un System.gc() à la fin de la méthode, les numéros de performance étaient plus cohérents avec l'itérateur gagnant:

108 143
89 152
83 148
78 140
79 153
90 155
...

Voir la réponse de Peter ici pour plus de détails: Temps d'exécution du processeur en Java

Pour une tonne de plus d'informations sur la façon de faire correctement le micro-benchmarking comme celui-ci, voir cette réponse exhaustive: Comment écrire un micro-benchmark correct dans Java?

 11
Author: Gray, 2017-05-23 12:07:37