kikulikov
kikulikov

Reputation: 2583

How do I measure elapsed time inside Cats IO effect?

I'd like to measure elapsed time inside IO container. It's relatively easy to do with plain calls or futures (e.g. something like the code below)

class MonitoringComponentSpec extends FunSuite with Matchers with ScalaFutures {

  import scala.concurrent.ExecutionContext.Implicits.global

  def meter[T](future: Future[T]): Future[T] = {
    val start = System.currentTimeMillis()
    future.onComplete(_ => println(s"Elapsed ${System.currentTimeMillis() - start}ms"))
    future
  }

  def call(): Future[String] = Future {
    Thread.sleep(500)
    "hello"
  }

  test("metered call") {
    whenReady(meter(call()), timeout(Span(550, Milliseconds))) { s =>
      s should be("hello")
    }
  }
}

But not sure how to wrap IO call

  def io_meter[T](effect: IO[T]): IO[T] = {
    val start = System.currentTimeMillis()
    ???
  }

  def io_call(): IO[String] = IO.pure {
    Thread.sleep(500)
    "hello"
  }

  test("metered io call") {
    whenReady(meter(call()), timeout(Span(550, Milliseconds))) { s =>
      s should be("hello")
    }
  }

Thank you!

Upvotes: 2

Views: 2081

Answers (2)

Abel Terefe
Abel Terefe

Reputation: 1470

In cats effect 3, you can use .timed. Like,

import cats.effect.IO
import cats.effect.unsafe.implicits.global
import cats.implicits._
import scala.concurrent.duration._

val twoSecondsLater = IO.sleep(2.seconds) *> IO.println("Hi")

val elapsedTime = twoSecondsLater.timed.map(_._1)
elapsedTime.unsafeRunSync()

// would give something like this. 
Hi
res0: FiniteDuration = 2006997667 nanoseconds

Upvotes: 2

Karl Bielefeldt
Karl Bielefeldt

Reputation: 49028

Cats-effect has a Clock implementation that allows pure time measurement as well as injecting your own implementations for testing when you just want to simulate the passing of time. The example from their documentation is:

def measure[F[_], A](fa: F[A])
  (implicit F: Sync[F], clock: Clock[F]): F[(A, Long)] = {

  for {
    start  <- clock.monotonic(MILLISECONDS)
    result <- fa
    finish <- clock.monotonic(MILLISECONDS)
  } yield (result, finish - start)
}

Upvotes: 8

Related Questions