Scala println和System.currentTimeMillis的奇怪行为
我运行以下代码:Scala println和System.currentTimeMillis的奇怪行为,scala,Scala,我运行以下代码: object Main { def main(args: Array[String]) = { { val start = System.currentTimeMillis println("took " + (System.currentTimeMillis - start) + " ms") } { val start = System.currentTimeMillis val took = Sy
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
为什么会这样?我猜这是因为JVM优化在运行时预热了一些东西,因为当我尝试降低代码时,我添加一个println调用的次数为零
我猜这是因为JVM优化在运行时预热了,因为当我尝试降低代码时,我添加一个println调用的次数为零 以下是两条建议: 1不要使用System.currentTimeMillis,而是使用System.nanoTime以获得更高的精度。 2在多次调用该方法10倍、100倍、100倍后,找到平均值 原因似乎是第一个块在println中调用System.currentTimeMillis,而第二个块在之前计算值 下面是我在println之外使用ns计算的第二个块样式调用该方法几次的结果 用了140纳秒 用119纳秒 用了150纳秒 服用132纳秒 以下是两条建议: 1不要使用System.currentTimeMillis,而是使用System.nanoTime以获得更高的精度。 2在多次调用该方法10倍、100倍、100倍后,找到平均值 原因似乎是第一个块在println中调用System.currentTimeMillis,而第二个块在之前计算值 下面是我在println之外使用ns计算的第二个块样式调用该方法几次的结果 用了140纳秒 用119纳秒 用了150纳秒 服用132纳秒
用129纳秒很难相信你能用这种方法测量出任何有意义的东西,所以这有点像猜测有多少天使能在一根针的头上跳舞 有一些选项可用于检查代码编译的目的:
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))
}
}
}
}
很难相信你能用这种方法测量出任何有意义的东西,所以这有点像猜测有多少天使能在一根针的头上跳舞 有一些选项可用于检查代码编译的目的:
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))
}
}
}
}
我自己可以用“nanoTime”替换“currentTimeMillis”,我知道将计算放在println之外可以解决问题。我对这种行为的本质感到好奇,而不是对如何修复它感到好奇。我自己可以用“nanoTime”替换“currentTimeMillis”,我知道将计算置于println之外可以解决问题。我很好奇这种行为的本质,而不是如何修复它。额外的类加载看起来是一个正确的答案,谢谢。额外的类加载看起来是一个正确的答案,谢谢。
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))
}
}
}
}
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;