如何在scala控制台中测量语句的时间?

时间:2012-03-03 15:12:34

标签: regex scala

我正在使用Scala来衡量java的正则表达式引擎的性能。下面的正则表达式大约在3秒内执行,但我无法使用System.currentTimeMillis进行测量。 (最后一个表达式返回0)

scala> val b = System.currentTimeMillis; val v = new Regex("(x+)+y").findAllIn("x"*25); b-System.currentTimeMillis
b: Long = 1330787275629
v: scala.util.matching.Regex.MatchIterator = empty iterator
res18: Long = 0

你现在为什么最后返回的值为0,而不是scala在执行regexp时花费的ms数量?

6 个答案:

答案 0 :(得分:81)

原因不明的持续时间来自于toString返回的迭代器上的REPL调用findAllIn。这又会调用Regex.MatchIterator#hasNext来触发搜索。

scala> def time[A](a: => A) = {
     |   val now = System.nanoTime
     |   val result = a
     |   val micros = (System.nanoTime - now) / 1000
     |   println("%d microseconds".format(micros))
     |   result
     | }
time: [A](a: => A)A

scala> :power
** Power User mode enabled - BEEP WHIR GYVE **
** :phase has been set to 'typer'.          **
** scala.tools.nsc._ has been imported      **
** global._, definitions._ also imported    **
** Try  :help, :vals, power.<tab>           **

scala> :wrap time
Set wrapper to 'time'

scala> new Regex("(x+)+y").findAllIn("x"*25).toString
3000737 microseconds
res19: String = empty iterator

scala> {new Regex("(x+)+y").findAllIn("x"*25); 0}
582 microseconds
res20: Int = 0

答案 1 :(得分:28)

def time[A](f: => A) = {
  val s = System.nanoTime
  val ret = f
  println("time: "+(System.nanoTime-s)/1e6+"ms")
  ret
}

将其用于:

scala> time { 10*2 }
time: 0.054212ms
res1: Int = 20

答案 2 :(得分:5)

这很有意思!我在创建正则表达式的行周围添加了println("start")"end"并运行了代码 - 这打印

start 
end

然后暂停约三秒钟,然后打印剩余的输出。

所以看起来正在发生的是正在创建的正则表达式,但是在调用toString之前不会运行,以便将其输出到控制台。要使测试起作用,请在计算花费的时间之前添加手动toString调用。

scala> val b = System.currentTimeMillis; val v = new scala.util.matching.Regex("(x+)+y").findAllIn("x"*25); v.toString; System.currentTimeMillis-b
b: Long = 1330789547209
v: scala.util.matching.Regex.MatchIterator = empty iterator
res14: Long = 4881

它也应该是System.currentTimeMillis-b而不是相反......

答案 3 :(得分:2)

这不是您问题的直接答案,但您可能需要考虑使用Criterium等成熟的基准测试库。

一般来说,基准测试和特别是JVM上存在许多陷阱(this是一个很好的讨论)。如果您推出自己的解决方案,那么避免它们并非易事。

答案 4 :(得分:1)

略有改进可能包括多次运行。如果你担心的不仅仅是相对速度差异,那么正确的基准测试库非常重要。

def time[A](a: => A, n:Int) = {
    var times = List[Long]()
        for (_ <- 1 to n) {
        val now = System.nanoTime
        val res = a
        times :::= List(System.nanoTime - now)
    }
    val result = times.sum / n
    println("%d microseconds".format(result / 1000))
    result
}

答案 5 :(得分:0)

还要考虑这种方法,用于返回应用方法的实际输出以及经过的时间,两者都在元组中(Scala 2.10 +),

implicit class RichElapsed[A](f: => A) {

  def elapsed(): (A, Double) = {
    val start = System.nanoTime()
    val res = f
    val end = System.nanoTime()

    (res, (end-start)/1e3)
  }

}

对于任何给定的函数def f(n: Int) = (1 to n) product

scala> val (res, time) = f(3).elapsed
res: Int = 6
time: Double = 46.4378