[英]Performance loss of continued call to array.length or list.size()
I have seen people say to cache the values of size
for a list or length
for an array when iterating, to save the time of checking the length/size over and over again.我见过有人说在迭代时缓存列表的size
值或数组的length
值,以节省一遍又一遍检查长度/大小的时间。
So所以
for (int i = 0; i < someArr.length; i++) // do stuff
for (int i = 0; i < someList.size(); i++) // do stuff
Would be turned into会变成
for (int i = 0, length = someArr.length; i < length; i++) // do stuff
for (int i = 0, size = someList.size(); i < size; i++) // do stuff
But since Array#length
isn't a method, just a field, shouldn't it not have any difference?但是既然Array#length
不是一个方法,只是一个字段,它不应该没有任何区别吗? And if using an ArrayList, size()
is just a getter so shouldn't that also be the same either way?如果使用 ArrayList, size()
只是一个吸气剂,那么这两种方式不应该相同吗?
It is possible the JIT compiler will do some of those optimizations for itself. JIT 编译器可能会为自己做一些优化。 Hence, doing the optimizations by hand may be a complete waste of time.因此,手动进行优化可能完全是浪费时间。
It is also possible (indeed likely) that the performance benefit you are going to get from hand optimizing those loops is too small to be worth the effort.也有可能(确实很可能)从手动优化这些循环中获得的性能优势太小,不值得付出努力。 Think of it this way:这样想:
The corollary is that:推论是:
Having said all of that:说了这么多:
theArr.length
is very fast, probably just a couple of machine instructions theArr.length
非常快,可能只有几条机器指令theList.size()
will probably also be very fast, though it depends on what List
class you are using. theList.size()
可能也会非常快,但这取决于您使用的List
class 。ArrayList
the size()
call is probably a method call + a field fetch versus a field fetch for length
.对于ArrayList
, size()
调用可能是方法调用 + 字段获取与length
的字段获取。ArrayList
the size()
call is likely to be inlined by the JIT compiler... assuming that the JIT compiler can figure that out.对于ArrayList
,JIT 编译器可能会内联size()
调用......假设 JIT 编译器可以解决这个问题。length
fetch out of the loop. JIT 编译器应该能够将length
提取提升到循环之外。 It can probably deduce that it doesn't change in the loop.它可能会推断它在循环中没有改变。size()
call, but it will be harder for it to deduce that the size doesn't change. JIT 编译器可能能够提升size()
调用,但它更难推断出大小没有改变。What this means is that if you do hand optimize those two examples, you will most likely get negligible performance benefit.这意味着如果您手动优化这两个示例,您很可能会获得微不足道的性能优势。
In general the loss is negligible.一般来说,损失可以忽略不计。 Even a LinkedList.size()
will use a stored count, and not iterate over all nodes.即使是LinkedList.size()
也会使用存储的计数,而不是遍历所有节点。
For large sizes you may assume the conversion to machine code may catch up, and optimize it oneself.对于大尺寸,您可能会假设转换为机器代码可能会赶上并自行优化。
If inside the loop the size is changed (delete/insert) the size variable must be changed too, which gives us even less solid code.如果在循环内部改变了大小(删除/插入),那么大小变量也必须改变,这给我们提供了更不可靠的代码。
The best would be to use a for-each最好的方法是使用 for-each
for (Bar bar: bars) { ... }
You might also use the somewhat more costing Stream:您也可以使用成本更高的 Stream:
barList.forEach(bar -> ...);
Stream.of(barArray).forEach(bar -> ...);
Streams can be executed in parallel.流可以并行执行。
barList.parallelStream().forEach(bar -> ...);
And last but not least you may use standard java code for simple loops:最后但并非最不重要的一点是,您可以使用标准 java 代码进行简单循环:
Arrays.setAll(barArray, i -> ...);
We are talking here about micro-optimisations .我们在这里谈论的是微优化。 I would go for elegance.为了优雅,我会选择 go。
Most often the problem is the used algorithm & datastructurs.最常见的问题是使用的算法和数据结构。 List
is notorious, as everything can be a List
. List
是臭名昭著的,因为一切都可以是List
。 However Set
or Map
often provide much higher power/expressiveness.然而Set
或Map
通常提供更高的功率/表现力。
If a complex piece of software is slow, profile the application.如果一个复杂的软件速度很慢,请分析应用程序。 Check the break lines: java collections versus database queries, file parsing.检查断线:java collections 与数据库查询、文件解析。
It is best not to call a method on every loop round, so you should avoid calling size() on the condition part that is evaluated on every round.最好不要在每一轮循环中调用方法,因此应避免在每轮评估的条件部分调用 size()。 If you use a for each loop, this does not apply.如果您使用 for each 循环,则不适用。
for (int i = 0; i < foos.bar(); i++) // slow
for (int i = 0, size = foos.bar(); i < size; i++) // fast
for (Foo foo : foo.bar()) // fast
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.