用开始时间和结束时间打印差异来包装 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))
)
}
一些建议:
Task
值应该是纯值,以及函数 returning Task
s — 触发副作用的函数和 return Task
作为结果坏了
Task
不是 1:1 替代 Future
;在描述 Task
时,所有的副作用都应该在 Task
中暂停(包装)
foreach
触发了 Task
的评估,这不好,因为它触发了副作用;我正在考虑弃用和删除它,因为它的存在很诱人
- 停止使用 trait 继承,只使用普通函数——除非你深刻理解 OOP 和子类型,否则最好尽可能避免;如果您喜欢 Cake 模式,请停止这样做并加入支持小组
- 永远不要通过
new Date()
测量持续时间,你需要一个单调时钟,并且在 System.nanoTime
的 JVM 之上,它可以通过 Monix 的 Scheduler
通过 clockMonotonic
,如上例所示,Scheduler
通过 deferAction
提供给您
- 停止阻塞线程,因为这很容易出错 — 不要做
Thread.sleep
,而是做 Task.sleep
并且所有 Await.result
调用都是有问题的,除非它们在 main
或在其他一些不可能处理异步的地方
希望这对您有所帮助。
干杯,
就像@Pierre 提到的,最新版本的 Monix Task 有 Task.timed
,你可以
timed <- task.timed
(duration, t) = timed
这就是我现在正在尝试的方法,但它只打印 "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))
)
}
一些建议:
Task
值应该是纯值,以及函数 returningTask
s — 触发副作用的函数和 returnTask
作为结果坏了Task
不是 1:1 替代Future
;在描述Task
时,所有的副作用都应该在Task
中暂停(包装)
foreach
触发了Task
的评估,这不好,因为它触发了副作用;我正在考虑弃用和删除它,因为它的存在很诱人
- 停止使用 trait 继承,只使用普通函数——除非你深刻理解 OOP 和子类型,否则最好尽可能避免;如果您喜欢 Cake 模式,请停止这样做并加入支持小组
- 永远不要通过
new Date()
测量持续时间,你需要一个单调时钟,并且在System.nanoTime
的 JVM 之上,它可以通过 Monix 的Scheduler
通过clockMonotonic
,如上例所示,Scheduler
通过deferAction
提供给您
- 停止阻塞线程,因为这很容易出错 — 不要做
Thread.sleep
,而是做Task.sleep
并且所有Await.result
调用都是有问题的,除非它们在main
或在其他一些不可能处理异步的地方
希望这对您有所帮助。
干杯,
就像@Pierre 提到的,最新版本的 Monix Task 有 Task.timed
,你可以
timed <- task.timed
(duration, t) = timed