Java foreach循环是否会重复执行

时间:2013-04-10 18:04:27

标签: java performance for-loop foreach garbage-collection

我同意foreach循环减少了输入并且有助于提高可读性。

一点点备份,我致力于低延迟应用程序开发,每秒接收1M亿个数据包。迭代一百万个数据包并将此信息发送给其侦听器。我正在使用foreach循环来遍历一组监听器。

进行性能分析我认为有很多 Iterator对象被创建来执行foreach循环。将foreach循环转换为基于索引的foreach我观察到通过减少no而在那里创建的对象数量大幅下降。 GC的增加和应用程序吞吐量的增加。

修改 :(抱歉混淆,让这个Q更清晰) 例如,我有听众列表(固定大小),我每秒循环这个forloop一百万次。在Java中,foreach是否过度杀伤?

示例:

for(String s:listOfListeners)
{
   // logic
}

相比
for (int i=0;i<listOfListeners.size();i++)
{
   // logic
}

代码的剖析截图

for (int cnt = 0; cnt < 1_000_000; cnt++)
{
    for (String string : list_of_listeners)
    {
         //No Code here 
    }
}

enter image description here

5 个答案:

答案 0 :(得分:10)

编辑:回答完全不同的问题:

  

例如,我有听众列表(固定大小),我每秒循环这个forloop一百万次。在Java中,foreach是否过度杀伤?

这取决于 - 您的分析是否实际显示额外分配重要? Java分配器和垃圾收集器每秒可以执行批次工作。

换句话说,您的步骤应该是:

  1. 设定绩效目标和功能要求
  2. 编写最简单的代码以实现功能要求
  3. 衡量该代码是否符合功能要求
  4. 如果它没有:
    • 配置文件以确定优化位置
    • 进行更改
    • 再次运行测试以查看它们是否会对您有意义的指标产生显着影响(分配的对象数量可能不是一个有意义的指标;您可以处理的侦听器数量可能是多少)
    • 返回第3步。
  5. 也许在你的情况下,增强的for循环很重要。我不会假设它是 - 我也不会认为每秒创建一百万个对象是重要的。我会在之前和之后测量有意义的指标...并确保在做其他任何事情之前有具体的绩效目标,否则你不知道何时停止微观优化。< / p>


      

    列表大小约为一百万个流媒体。

    所以你要创建一个迭代器对象,但是你要执行你的循环体一百万次。

      

    进行性能分析我认为有很多Iterator对象被创建来执行foreach循环。

    都能跟得上?只应创建单个迭代器对象。 As per the JLS

      

    增强的for语句相当于表单的基本for语句:

        for (I #i = Expression.iterator(); #i.hasNext(); ) {
            VariableModifiersopt TargetType Identifier =
                (TargetType) #i.next();
            Statement
        }
    

    如您所见,它会调用iterator()方法一次,然后在每次迭代时调用hasNext()next()

    您是否认为额外的对象分配会显着损害您的表现?

    您认为可读性与性能相比有多大?我采用了增强型for循环的方法,只要它有助于提高可读性,直到它被证明是一个性能问题 - 而我个人的经验是它永远不会在任何事情上显着损害性能#&# 39;写了。这并不是说所有应用程序都适用,但默认位置应该只是在证明它会显着改善之后才使用可读性较低的代码。

答案 1 :(得分:6)

“foreach”循环只创建一个Iterator对象,而第二个循环则不创建任何对象。如果你正在执行很多很多单独的循环,每个循环只执行几次,那么是的,“foreach”可能会不必要地昂贵。否则,这是微观优化。

答案 2 :(得分:1)

编辑:问题发生了很大变化,因为我写了答案,我不确定我现在正在回答什么。

使用list.get(i)查找内容实际上可能会慢很多,如果它是链接列表,因为对于每个查找,它必须遍历列表,而迭代器会记住位置。

示例:

list.get(0) will get the first element
list.get(1) will first get the first element to find pointer to the next
list.get(2) will first get the first element, then go to the second and then to the third
etc.

所以要做一个完整循环,你实际上是以这种方式循环元素:

0
0->1
0->1->2
0->1->2->3
etc.

答案 3 :(得分:0)

我认为你不应该担心这里的有效性。

大部分时间都是由您的实际应用程序逻辑消耗的(在这种情况下 - 通过您在循环中执行的操作)。

所以,我不担心你为方便起见付出的代价。

答案 4 :(得分:0)

这种比较是否公平?您正在使用Iterator

使用get(index) V进行比较

此外,每个循环只会创建一个额外的Iterator。除非Iterator由于某种原因本身效率低下,否则你应该看到相似的表现。