简体   繁体   English

为什么 Queue.poll 比 Iteration 快? (java.util.concurrent.ConcurrentLinkedQueue)

[英]Why is Queue.poll faster than Iteration? (java.util.concurrent.ConcurrentLinkedQueue)

I have a piece of code that gets all the elements from a queue.我有一段代码可以从队列中获取所有元素。 I do not care about the state of the queue afterwards and I can be assured the queue will not be modified while I am removing the elements from it.之后我不关心队列的状态,我可以保证在我从队列中删除元素时队列不会被修改。

I was initially using an iterator to pull the elements because I thought it would be faster than polling the elements...我最初使用迭代器来拉取元素,因为我认为它比轮询元素更快......

but i ran the following test:但我进行了以下测试:

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);

I got the following output (average over 100 runs)我得到以下输出(平均超过 100 次运行)

1169 46

My question is: Why is poll faster than iterate?我的问题是:为什么轮询比迭代快? It is completely unintuitive to me because poll will have to modify the queue and iterate will only have to look at the state.这对我来说完全不直观,因为 poll 必须修改队列,而 iterate 只需要查看状态。

edit --- Gray was right编辑---格雷是对的

I ran it in a loop and got the output (should have done this in the first place)我在循环中运行它并得到输出(首先应该这样做)

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
...

My question is: Why is poll faster than iterate?我的问题是:为什么轮询比迭代快? It is completely unintuitive to me because poll will have to modify the queue and iterate will only have to look at the state.这对我来说完全不直观,因为 poll 必须修改队列,而 iterate 只需要查看状态。

This seems to be, as @csoroiu points out, a hotspot compiler issue.正如@csoroiu 指出的那样,这似乎是一个热点编译器问题。 Given how Java works, it is very important that you "warm up" your application before you start doing timing calls like this.鉴于 Java 的工作原理,在开始执行这样的计时调用之前“预热”应用程序非常重要。

If I run your tests 100 times in a method I initially saw vastly different performance due to GC overhead and other JVM magic.如果我在一个方法中运行您的测试 100 次,由于 GC 开销和其他 JVM 魔法,我最初看到的性能有很大不同。 However, after adding some .clear() methods and a System.gc() at the end of the method, the performance numbers were more consistent with the iterator winning:但是,在方法.clear()添加一些.clear()方法和System.gc()后,性能数字与迭代器获胜更加一致:

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

See Peter's answer here for some more details: CPU execution time in Java有关更多详细信息,请参阅 Peter 在此处的回答: Java 中的 CPU 执行时间

For a ton of more information about how to properly do micro-benchmarking like this, see this exhaustive answer: How do I write a correct micro-benchmark in Java?有关如何正确执行此类微基准测试的更多信息,请参阅此详尽答案: 如何在 Java 中编写正确的微基准测试?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM