我正在使用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数量?
答案 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