用开始时间和结束时间包装monix Task的最佳方法是什么?

时间:2018-06-22 09:20:49

标签: scala monix

这是我现在正在尝试的方法,但它仅显示“嘿”,而不显示指标。 我不想在主要功能中添加与指标相关的内容。

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)

2 个答案:

答案 0 :(得分:7)

您可以描述这样的功能:

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的值应该是纯净的,并且返回Task的函数应该是纯函数,这些函数会触发副作用并在结果被破坏时返回Task
    • Task不是Future的1:1替代;描述Task时,应将所有副作用都Task中暂停(包装)
    • foreach触发Task的评估,但效果不好,因为它会触发副作用;我一直在考虑弃用和删除它,因为它的存在很诱人
  2. 停止使用特征继承,而只使用简单的函数—除非您对OOP和子类型有深刻的了解,否则最好避免使用它;如果您喜欢“蛋糕”模式,请停止这样做,并加入支持小组
  3. 永远不要通过new Date()来测量持续时间,为此您需要一个单调时钟,并且在System.nanoTime的JVM之上,{{1}可以通过Monix的Scheduler访问它。 },如以上示例所示,clockMonotonic是通过Scheduler
  4. 给您的
  5. 停止阻塞线程,因为这容易出错-除非执行deferAction,而是执行Thread.sleep,否则所有Task.sleep的调用都是有问题的,除非它们位于Await.result或某些位置在不可能处理异步的其他地方

希望这会有所帮助。

干杯

答案 1 :(得分:2)

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

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