为什么Scala 3中用while循环填充Array[Int]比Array.fill慢100倍?
Scala 3 手动while循环填充数组性能异常问题说明
我实现了两种填充Array[Int]的方式,测试结果如下。第一种执行耗时84ms,第二种速度慢100倍:
Execute 'filling via Array.fill' in 84 ms Execute 'filling via while' in 8334 ms
为什么第二种实现耗时高100倍?这不是GC导致的,我去掉第一个执行逻辑后,第二个的耗时依然不变。测试环境为Scala 3、Java 11,执行命令如下:
.jdks/adopt-openjdk-11.0.11/bin/java ... Fill
另外如果查看Array.fill的实现,会发现它底层也是通过while实现的,完整测试代码如下:
object Fill extends App { def timeMeasure[R](name: String)(block: => R): R = { val startTime = System.currentTimeMillis() val r = block val endTime = System.currentTimeMillis() println(s"Execute '$name' in ${endTime - startTime} ms") r } val n = 1000 * 1000 // * 10 var ar = timeMeasure("filling via Array.fill") { Array.fill[Int](n)(10) } ar = timeMeasure("filling via while") { val array = new Array[Int](n) var i = 0 while (i < n) { array(i) = i i += 1 } array } }
PS:我在Scala 2.12上重复了该测试,结果如下:
Execute 'filling via Array.fill' in 118 ms Execute 'filling via while' in 6 ms
因此可以确定问题出在Scala 3上。
PPS:该场景下使用for (i <- 0 until n)的速度正常,耗时和Scala 2.12的表现一致。但也有部分场景下for循环的速度比while慢2到3倍。
PPPS:针对认为这是随机误差的观点,我可以确认不是:我执行了100次测试,总耗时516秒(测试当天我的PC运行速度更快),平均耗时仍然很高。而且部分程序中的代码块只会执行一次,并非所有性能测试都适合取平均耗时。
更新:我发现当val n定义在代码块外部时,执行速度会慢约1000倍,目前暂不清楚背后的原因,该问题已在Scala 3编译器仓库有相关讨论。
内容的提问来源于stack exchange,提问作者Mikhail Ionkin
相关产品推荐
相关产品推荐

