我运行以下代码:
object Main {
def main(args: Array[String]) = {
{
val start = System.currentTimeMillis
println("took " + (System.currentTimeMillis - start) + " ms")
}
{
val start = System.currentTimeMillis
val took = System.currentTimeMillis - start
println(s"took $took ms")
}
}
}
它给出了:
took 246 ms
took 0 ms
但是如果我交换两个区块,那么我得到
took 0 ms
took 0 ms
为什么会这样?
答案 0 :(得分:3)
很难相信你能用这种方式测量任何有意义的东西,所以这有点像是猜测有多少天使可以在针头上跳舞。
有检查代码编译内容的选项:
apm@mara:~/tmp$ skalac -Xprint:typer angeldance.scala
[[syntax trees at end of typer]] // angeldance.scala
package angeldance {
object Main extends scala.AnyRef {
def <init>(): angeldance.Main.type = {
Main.super.<init>();
()
};
def main(args: Array[String]): Unit = {
{
val start: Long = java.this.lang.System.currentTimeMillis();
scala.this.Predef.println("took ".+(java.this.lang.System.currentTimeMillis().-(start)).+(" ms"))
};
{
val start: Long = java.this.lang.System.currentTimeMillis();
val took: Long = java.this.lang.System.currentTimeMillis().-(start);
scala.this.Predef.println(scala.StringContext.apply("took ", " ms").s(took))
}
}
}
}
在第二种情况下,StringContext.s
正在使用java.lang.StringBuilder
,而第一种情况下的表达式正在使用scala/collection/mutable/StringBuilder
。这可能会导致课堂上的费用增加。尝试-XX:+PrintClassLoading
时,你必须非常好奇。将其调用为scala -J-XX:+PrintClassLoading
。
scala> val i = 5L
i: Long = 5
scala> "hello, " + i
res0: String = hello, 5
scala> :javap -
Size 1007 bytes
MD5 checksum bbccca3ecafe9287f07df81ea123676e
Compiled from "<console>"
[snip]
8: aload_0
9: new #23 // class scala/collection/mutable/StringBuilder
12: dup
13: invokespecial #24 // Method scala/collection/mutable/StringBuilder."<init>":()V
16: ldc #26 // String hello,
18: invokevirtual #30 // Method scala/collection/mutable/StringBuilder.append:(Ljava/lang/Object;)Lscala/collection/mutable/StringBuilder;
21: getstatic #35 // Field .MODULE$:L;
24: invokevirtual #39 // Method .i:()J
27: invokestatic #45 // Method scala/runtime/BoxesRunTime.boxToLong:(J)Ljava/lang/Long;
30: invokevirtual #30 // Method scala/collection/mutable/StringBuilder.append:(Ljava/lang/Object;)Lscala/collection/mutable/StringBuilder;
33: invokevirtual #48 // Method scala/collection/mutable/StringBuilder.toString:()Ljava/lang/String;
答案 1 :(得分:2)
我猜这是JVM的预热(运行时的优化?),因为当我尝试降低代码时,它会给我零次(我添加了一个println
调用)。
object Main {
def main(args: Array[String]) {
println("x")
val a = ()=> {
val start = System.currentTimeMillis
println("took " + (System.currentTimeMillis - start) + " ms")
}
val b = ()=> {
val start = System.currentTimeMillis
val took = System.currentTimeMillis - start
println(s"took $took ms")
}
a()
b()
}
}
x took 0 ms took 0 ms
答案 2 :(得分:1)
以下是两条建议:
1)使用System.currentTimeMillis
而不是使用System.nanoTime
,以获得更高的精度。
2)多次调用该方法后找到平均值(10x,100x,..)。
原因似乎是你在println中的第一个块调用System.currentTimeMillis
,而第二个块计算之前的值。
这是我的结果以第二个块的样式调用该方法几次(在println外部计算),并使用ns。
耗时140 ns 耗时119 ns 耗时150 ns 耗时132 ns 耗时129 ns