30 votes

Comment mesurer le temps d'une déclaration dans la console scala?

J'utilise Scala pour mesurer les performances du moteur regex de java. L'expression régulière ci-dessous s'exécute en environ 3 secondes, mais je ne suis pas en mesure de la mesurer à l'aide de System.currentTimeMillis. (la dernière expression renvoie 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
 

Savez-vous maintenant pourquoi la dernière valeur renvoyée est 0, et non la quantité de ms que scala dépense pour exécuter l'expression rationnelle?

81voto

retronym Points 35066

La durée inexpliquée vient du REPL appelant toString sur l'itérateur renvoyé de findAllIn . Cela appelle à son tour Regex.MatchIterator#hasNext , ce qui déclenche la recherche.

 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
 

28voto

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

Utilisez-le avec:

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

5voto

Russell Points 5472

C'est très intéressant! J'ai ajouté un println("start") et "end" autour de la ligne qui crée la regex et a couru le code imprime

start 
end

puis s'interrompt pendant environ trois secondes avant l'impression le reste de la sortie.

De sorte qu'il ressemble à ce qui se passe est que l'expression régulière est en cours de création mais pas de fonctionner jusqu' toString est appelé pour la sortie de la console. Pour que le test fonctionne, ajoutez un manuel toString appel avant de calculer le temps passé.

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

Il doit aussi être System.currentTimeMillis-b plutôt que l'inverse...

2voto

Paul Butcher Points 5349

Ce n'est pas une réponse directe à votre question, mais vous voudrez peut-être envisager d'utiliser une bibliothèque de benchmarking mature comme Criterium .

Il y a beaucoup de pièges associés à l' analyse comparative en général et sur la machine virtuelle Java en particulier ( c'est une bonne discussion). Il n'est pas trivial de les éviter si vous lancez votre propre solution.

1voto

ramatevish Points 11

Une légère amélioration pourrait inclure plusieurs exécutions. Cependant, une bibliothèque de benchmarking appropriée est vraiment importante si vous êtes préoccupé par plus que les différences de vitesse relative.

 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
}
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X