Last active
May 7, 2018 01:45
-
-
Save dalegaspi/ce6167dc529cb8246e8f0be0f615c91b to your computer and use it in GitHub Desktop.
A simple stopwatch implementation for wall-clock time measurement of a sync of async method in scala
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.typesafe.scalalogging.StrictLogging | |
import monix.eval.Task | |
import monix.execution.Scheduler | |
import scala.concurrent.Future | |
object Stopwatch extends StrictLogging { | |
/** | |
* http://biercoff.com/easily-measuring-code-execution-time-in-scala/ | |
* | |
* @param block | |
* @param reporter | |
* @tparam R | |
* @return | |
*/ | |
def time[R](block: => R, | |
taskName: String = "process", | |
reporter: (String, Long) => Unit = (name, elapsedNanos) => { | |
logger.info(s"${name} elapsed time ${elapsedNanos} ns") | |
}): R = { | |
val t0 = System.nanoTime() | |
val result = block | |
val t1 = System.nanoTime() | |
reporter(taskName, t1 - t0) | |
result | |
} | |
/** | |
* async version of [[time]] | |
* | |
* ok this warrants a bit of explanation since this is something i added | |
* | |
* measuring execution time a Future directly is impossible unless you jerry-rig your Future | |
* with a parameter to kick off the t0 value (which is inelegant). | |
* why? because Futures are eagerly-evaluated--i.e., they are executed as soon | |
* as they are evaluated. also, any successive evaluation of the same future | |
* returns a memoized value. | |
* | |
* as of this writing there isn't a native lazily-evaluated Future object. luckily | |
* there is this awesome library called Monix that has an entity called [[Task]] | |
* that's essentially a "lazily-evaluated Future". it requires a [[Scheduler]] which is | |
* more-or-less the [[scala.concurrent.ExecutionContext]] used for execution of the | |
* resulting [[Future]] | |
* | |
* this returns a [[Future]] instead of a [[Task]] since for most use cases you want | |
* to just time it as is or chain them with other [[Future]]s. | |
* | |
* @param block | |
* @param taskName | |
* @param reporter | |
* @param scheduler | |
* @tparam R | |
* @return | |
*/ | |
def timeAsync[R](block: => Task[R], | |
taskName: String = "process", | |
reporter: (String, Long) => Unit = (name, elapsedNanos) => { | |
logger.info(s"${name} elapsed time ${elapsedNanos} ns") | |
})(implicit scheduler: Scheduler): Future[R] = { | |
val t0 = System.nanoTime() | |
val result = block.runAsync | |
result onComplete { | |
_ => val t1 = System.nanoTime() | |
reporter(taskName, t1 - t0) | |
} | |
result | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment