【问题标题】:Are there performance implications when using ArrayList.get() many times per iteration?每次迭代多次使用 ArrayList.get() 是否会影响性能?
【发布时间】:2017-07-15 10:35:00
【问题描述】:

对于一般的 Android 开发,执行以下操作是否更昂贵: (例一)

for(int x=0; x < largeObjectCollection.size(); x++){
    largeObjectCollection.get(x).SomeValueOne   = "Sample Value 1";
    largeObjectCollection.get(x).SomeValueTwo   = "Sample Value 2";
    largeObjectCollection.get(x).SomeValueThree = "Sample Value 3" ;
    //Continues on to over 30 properties...
}

关于这个实现(示例 2)

for(int x=0; x < largeObjectCollection.size(); x++){
   SampleObjectIns myObject = largeObjectCollection.get(x);
   myObject.SomeValueOne   = "Sample Value 1";
   myObject.SomeValueTwo   = "Sample Value 2";
   myObject.SomeValueThree = "Sample Value 3" ;
   //Continues on to over 30 properties...
}

当多次使用 .get() 而不是每次迭代都创建该对象的新实例时,我找不到任何性能影响细分。

我认为.get() 在资源方面的使用并不多,因为元素的位置是已知的,但是在处理许多属性时,最好只获取该对象一次,如示例二所示?

【问题讨论】:

  • 对于ArrayList(或其他RandomAccess 类),性能差异将很小。当然,如果你不需要xfor (SampleObjectIns myObject : largeObjectCollection) {,使用增强的for循环会更整洁;但这基本上是第二种方式。
  • @AndyTurner 谢谢,我正在阅读 2015 年 (blog.jooq.org/2015/02/05/…) 的一篇文章,指出迭代器实际上效率不高,第 3 条。这让我想到了我的代码,它主要使用enhanced-for-loops,因此出现了这个问题。您是否推荐任何涵盖这些主题的书籍?
  • 这一点的第一行:“现在,这个建议确实不适用于一般用例”。您问题的第一行:“对于一般的 Android 开发”。
  • @AndyTurner 好点

标签: java android performance


【解决方案1】:

在循环结构中多次调用get() 方法不会影响性能。

get() 方法不做任何搜索。该位置是已知的,因此 RAM 中的确切位置也是已知的。因此,它只需要进行一次 RAM 访问,这是一个 c即时操作 - O(1)

因此,您可以多次使用它而不会影响性能。但更简洁的方法是使用 get() 一次,将其存储在局部变量中,然后再使用该变量。

【讨论】:

  • 我对 Divers 的回答发表了相同的评论:“不,这与 O(1) 无关,因为列表的大小在两种情况之间没有变化。O 的操作(n)(或更糟)对于一些固定的 n 来说,可能比另一个操作 O(1) 花费的时间更少。Big-oh 是渐近分析:当你有一个固定大小的输入时,它没有任何意义。 .
【解决方案2】:

第一种情况显然会做更多的工作。至少有两种可能:

  • JIT 可能能够确定列表值没有变化,并且您重复请求相同的值;因此它有效地将其转换为第二种形式。
  • ArrayList.get 操作非常快;它基本上只是在进行数组查找,并且它查找的值已经在缓存中,因为您刚刚查找了它。

    因此,您的时间测量主要由您正在做的其他工作主导。因此,即使您的 get 调用次数超过了必要的 29 次,小数字的 30 倍仍然是小数字。

【讨论】:

  • 很好的分解。我不知道 JIT 能够确定值没有改变并转换为第二种形式。 “你的计时测量主要由你正在做的其他工作主导。” - 我会记住这一点并切换回我增强的 for 循环。
【解决方案3】:

唯一的原因是,get 对数组的操作非常快,这就是为什么性能几乎没有显着差异的原因。

【讨论】:

  • 两者具有相同的时间复杂度并不意味着它们在性能上没有差异。无论输入大小都需要 1 秒的东西显然比输入大小需要 1us 的东西更糟糕;但它们都是 O(1)。
  • 没找到你。两者都是什么?
  • 他在问为什么使用 get 操作 30 次与使用 get 操作 1 次几乎没有区别。我回答他,因为getoperation 不依赖于列表的大小,而且因为它的操作非常快,所以他不会看到明显的差异。
  • 对;但你的解释没有描述这一点。您说性能没有差异的事实是因为它是 O(1),这不是原因。原因是它很快,而做其他事情所花费的时间占主导地位。
  • 不,这与 O(1) 无关,因为列表的大小在两种情况下没有变化。对于某个固定的 n,一个 O(n)(或更糟)的操作可能比另一个 O(1) 的操作花费更少的时间。大哦是渐近分析:当你有一个固定大小的输入时,它没有任何意义。
猜你喜欢
  • 1970-01-01
  • 2019-01-21
  • 2019-10-01
  • 2013-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-18
  • 1970-01-01
相关资源
最近更新 更多