简体   繁体   English

Java for循环性能

[英]Java for loop performance

What is better in for loop 什么是更好的for循环

This: 这个:

for(int i = 0; i<someMethod(); i++)
{//some code
 }

or: 要么:

int a = someMethod();
for(int i = 0; i<a; i++)
{//some code
 }

Let's just say that someMethod() returns something large. 我们只是说someMethod()返回一些大的东西。

First method will execute someMethod() in each loop thus decreasing speed, second is faster but let's say that there are a lot of similar loops in application so declaring a variable vill consume more memory. 第一种方法将在每个循环从而降低速度执行的someMethod(),第二个是更快,但让我们说,有很多在应用类似的环,以便声明变量 VILL的消耗更多的存储器。

So what is better, or am I just thinking stupidly. 那么更好,或者我只是愚蠢地思考。

The second is better - assuming someMethod() does not have side effects . 第二个更好 - 假设someMethod()没有副作用
It actually caches the value calculated by someMethod() - so you won't have to recalculate it (assuming it is a relatively expansive op). 它实际上缓存了someMethod()计算的值 - 所以你不必重新计算它(假设它是一个相对广泛的操作)。

If it does (has side effects) - the two code snaps are not equivalent - and you should do what is correct . 如果它(有副作用) - 两个代码捕捉不相等 - 你应该做正确的事情。

Regarding the "size for variable a" - it is not an issue anyway, the returned value of someMethod() needs to be stored on some intermediate temp variable anyway before calculation (and even if it wasn't the case, the size of one integer is negligible). 关于“变量a的大小” - 无论如何都不是问题, someMethod()的返回无论如何都需要在计算之前存储在某个中间临时变量上 (即使不是这样,一个大小也是如此)整数可以忽略不计)。

PS PS
In some cases, compiler / JIT optimizer might optimize the first code into the second, assuming of course no side effects. 在某些情况下,编译器/ JIT优化器可能会将第一个代码优化为第二个代码,假设当然没有副作用。

If in doubt, test. 如有疑问,请测试。 Use a profiler. 使用分析器。 Measure. 测量。

Assuming the iteration order isn't relevant, and also assuming you really want to nano-optimize your code, you may do this : 假设迭代顺序不相关,并且假设您真的想要对代码进行纳米优化,那么您可以这样做:

for (int i=someMethod(); i-->0;) {
  //some code
}

But an additional local variable (your a ) isn't such a burden. 但是另外一个局部变量(你的a )并不是一个负担。 In practice, this isn't much different from your second version. 在实践中,这与您的第二个版本没有太大区别。

If you don't need this variable after loop, there is simple way to hide it inside: 如果你在循环后不需要这个变量,有一种简单的方法可以将其隐藏在里面:

for (int count = someMethod (), i = 0; i < count; i++)
{
    // some code
}

It really depends how long it takes to generate the output of someMethod(). 这实际上取决于生成someMethod()的输出所需的时间。 Also the memory usage would be the same, because someMethod() first has to generate the output and stores this then. 内存使用量也是一样的,因为someMethod()首先必须生成输出然后存储它。 The second way safes your cpu from computing the same output every loop and it should not take more memory. 第二种方法保护你的cpu从每个循环计算相同的输出,它不应该占用更多的内存。 So the second one is better. 所以第二个更好。

I would not consider the memory consumption of the variable a as a problem as it is an int and requires 192 bit on a 64 bit machine. 我不会将变量a的内存消耗视为一个问题,因为它是一个int并且在64位机器上需要192位。 So I would prefer the second alternative as it execution efficiency is better. 所以我更喜欢第二种选择,因为它的执行效率更高。

The most important part about loop optimizations is allowing the JVM to unroll the loop. 关于循环优化的最重要部分是允许JVM展开循环。 To do so in the 1st variant it has to be able to inline the call to someMethod() . 要在第一个变体中执行此操作,它必须能够内联对someMethod()的调用。 Inlining has some budget and it can get busted at some point. 内联有一些预算,可能会在某些时候被破坏。 If someMethod() is long enough the JVM may decide it doesn't like to inline. 如果someMethod()足够长,JVM可能会认为它不喜欢内联。

The second variant is more helpful (to JIT compiler) and likely to work better. 第二个变体更有用(对JIT编译器)并且可能更好地工作。

my way for putting down the loop is: for (int i=0, max=someMethod(); i<max; i++){...} 我放弃循环的方法是: for (int i=0, max=someMethod(); i<max; i++){...}

max doesn't pollute the code, you ensure no side effects from multiple calls of someMethod() and it's compact (single liner) max不会污染代码,你可以确保someMethod()的多次调用没有副作用,而且紧凑(单线程)

If you need to optimize this, then this is the clean / obvious way to do it: 如果你需要优化它,那么这是干净/明显的方法:

int a = someMethod();
for (int i = 0; i < a; i++) {
    //some code
}

The alternative version suggested by @dystroy @dystroy建议的替代版本

for (int i=someMethod(); i-->0;) {
    //some code
}

... has three problems. ......有三个问题。

  • He is iterating in the opposite direction. 他在相反的方向迭代。

  • That iteration is non-idiomatic, and hence less readable. 该迭代是非惯用的,因此不太可读。 Especially if you ignore the Java style guide and don't put whitespace where you are supposed to. 特别是如果您忽略Java样式指南并且不将空格放在您应该的位置。

  • There is no proof that the code will actually be faster than the more idiomatic version ... especially once the JIT compiler has optimized them both. 没有证据表明代码实际上会比更惯用的版本更快......尤其是一旦JIT编译器对它们进行了优化。 (And even if the less readable version is faster, the difference is likely to be negligible.) (即使可读性较低的版本更快,差异也可能微不足道。)

On the other hand, if someMethod() is expensive (as you postulate) then "hoisting" the call so that it is only done once is likely to be worthwhile. 另一方面,如果someMethod()是昂贵的(如你所假设的那样),那么“提升”调用以便它只进行一次可能是值得的。

I was a bit confused about the same and did a sanity test for the same with a list of 10,000,000 integers in it. 我对此有点困惑,并对其进行了一次完整性测试,其中包含10,000,000个整数列表。 Difference was more than two seconds with latter being faster: 差异超过两秒,后者更快:

int a = someMethod(); for(int i = 0; i<a; i++) {//some code }

My results on Java 8 (MacBook Pro, 2.2 GHz Intel Core i7) were: 我在Java 8(MacBook Pro,2.2 GHz Intel Core i7)上的结果如下:

using list object: Start- 1565772380899, End- 1565772381632 使用列表对象:Start- 1565772380899,End-1565772381632

calling list in 'for' expression: Start- 1565772381633, End- 1565772384888 在'for'表达式中调用列表:Start- 1565772381633,End-1565772384888

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

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