最近在研究我们产品的代码,看到了一段类似下面的代码:x.set(1)x.set(2)x.set(3)x.set(4)x.set(5)我当时很疑惑,为什么不用循环呢?于是报了一个Issue,觉得这样写可能是有原因的,但需要澄清一下。另一个问题是我发现在代码中有不同的方式来使用循环。有人写array.foreach(f=>_),有人用for循环usingindex。个人觉得使用foreach的代码更简洁,所以也报了Issue,看看循环要不要写的简洁一些。示例:for循环varindex=0vararr=Array[String]varlength=arr.lengthfor(index<-0tolength){do()}foreachvarindex=0vararr=Array[String]varlength=arr.lengthfor(index<-0tolength){do()}显然foreach版本节省了大量代码。跟我们的工程师沟通后,原来我们是为了性能优化了代码,因为for循环的性能比foreach要好,所以我们使用了稍微繁琐的for循环。至于一些代码中的foreach,是因为遗留的还没来得及改。Scala的循环性能如何?我最好测试一下。让我们来看看不同的循环用法。我这里测试了四种,分别是while循环、for循环、foreachusingrange、foreachusingfunctions。测试代码如下:packageprofilingobjectLoop{defwhileLoop(arr:Array[Int]):Unit={varidx=0varn=arr.lengthvaltStart=System.currentTimeMillis()while(idxarr(idx)=1}valtEnd=System.currentTimeMillis()println("foreachrangetook"+(tEnd-tStart)+"ms")}defforeachFuncLoop(arr:Array[Int]):Unit={valtStart=System.currentTimeMillis()arr.foreach{idx=>arr(idx)=1}valtEnd=System.currentTimeMillis()println("foreachfunctiontook"+(tEnd-tStart)+"ms")}defprofileRun(n:Int){valarr=newArray[Int](n)whileLoop(arr)foreachLoop(arr)forLoop(arr)foreachFuncLoop(arr)}defmain(args:Array[String]){profileRun(args(0).toInt)}}我的环境是scala2.13.1,调用500000000第二个结果是:Bash代码whilelooptook344msforeachrangetook484msforlooptook422msforeachfunctiontook719ms可见while循环是最快的,一般形式的foreach最慢,几乎是while循环的两倍。但是如果你使用range,foreach循环也不会太慢。那么为什么foreach很慢呢?主要原因是foreach的函数调用带来了额外的开销。上面我们看到的数据其实是编译器优化后的数字。如果我们把java的热点编译选项关掉,(-Xint)再看性能。whilelooptook8548msforeachrangetook39392msforlooptook40799msforeachfunctiontook103489ms如果关闭JIT,foreach的性能比其他选项差很多。关于循环的性能,我们可以得出以下结论:在正常开启JIT的情况下,foreach的性能大约是其他选项的两倍,而其他选项的性能接近JIT开启时的性能优化已关闭。foreach的性能远低于其他选项(生产环境一般不考虑)。那么不在开头循环直接重复代码呢?我们还对其进行了测试:packageprofilingobjectLoop2Repeat{defwhileLoop():Unit={varidx=0varn=5varx=0while(idxUnit,num:Int,name:String):Unit={valtStart=System.currentTimeMillis()(0untilnum).foreach{_=>f}valtEnd=System。currentTimeMillis()println(name+"took"+(tEnd-tStart)+"ms")}defmain(args:Array[String]){test(whileLoop,50000000,"whileLoop")test(repeatLoop,50000000,"repeatLoop")}}50000000次循环后,数据如下:whileLooptook281msrepeatLooptook47ms确实,因为循环控制的逻辑带来的额外开销比简单重复代码的性能要低很多。