用开始时间和结束时间打印差异来包装 monix 任务的最佳方法是什么?

What's the best way to wrap a monix Task with a start time and end time print the difference?

这就是我现在正在尝试的方法,但它只打印 "hey" 而不是指标。 我不想在主函数中添加指标相关的东西。

import java.util.Date

import monix.eval.Task
import monix.execution.Scheduler.Implicits.global

import scala.concurrent.Await
import scala.concurrent.duration.Duration

class A {
  def fellow(): Task[Unit] = {
    val result = Task {
      println("hey")
      Thread.sleep(1000)
    }
    result
  }
}

trait AA extends A {
  override def fellow(): Task[Unit] = {
    println("AA")
    val result = super.fellow()
    val start = new Date()
    result.foreach(e => {
      println("AA", new Date().getTime - start.getTime)
    })
    result
  }
}

val a = new A with AA
val res: Task[Unit] = a.fellow()
Await.result(res.runAsync, Duration.Inf)

您可以这样描述函数:

def measure[A](task: Task[A], logMillis: Long => Task[Unit]): Task[A] =
  Task.deferAction { sc =>
    val start = sc.clockMonotonic(TimeUnit.MILLISECONDS)
    val stopTimer = Task.suspend {
      val end = sc.clockMonotonic(TimeUnit.MILLISECONDS)
      logMillis(end - start)
    }

    task.redeemWith(
      a => stopTimer.map(_ => a)
      e => stopTimer.flatMap(_ => Task.raiseError(e))
    )
  }

一些建议:

  1. Task 值应该是纯值,以及函数 returning Tasks — 触发副作用的函数和 return Task 作为结果坏了
    • Task 不是 1:1 替代 Future;在描述 Task 时,所有的副作用都应该在 Task
    • 中暂停(包装)
    • foreach 触发了 Task 的评估,这不好,因为它触发了副作用;我正在考虑弃用和删除它,因为它的存在很诱人
  2. 停止使用 trait 继承,只使用普通函数——除非你深刻理解 OOP 和子类型,否则最好尽可能避免;如果您喜欢 Cake 模式,请停止这样做并加入支持小组
  3. 永远不要通过 new Date() 测量持续时间,你需要一个单调时钟,并且在 System.nanoTime 的 JVM 之上,它可以通过 Monix 的 Scheduler 通过 clockMonotonic,如上例所示,Scheduler 通过 deferAction
  4. 提供给您
  5. 停止阻塞线程,因为这很容易出错 — 不要做 Thread.sleep,而是做 Task.sleep 并且所有 Await.result 调用都是有问题的,除非它们在 main 或在其他一些不可能处理异步的地方

希望这对您有所帮助。

干杯,

就像@Pierre 提到的,最新版本的 Monix Task 有 Task.timed,你可以

timed <- task.timed
(duration, t) = timed