【问题标题】:Scalaz task firstCompletedOfScalaz 任务 firstCompletedOf
【发布时间】:2017-06-30 14:47:23
【问题描述】:
我有两个 scalaz.concurrent.Tasks 正在向不同的服务器执行 HTTP 请求。
我想以类似于Future.firstCompletedOf的方式组合它们,即:并行运行它们并获得第一个成功完成的结果。
不幸的是,Task.gatherUnordered 不是我想要的,因为它会在返回结果之前运行所有任务直到完成。
【问题讨论】:
标签:
scala
functional-programming
scalaz
【解决方案1】:
不知道如何在 scalaz.concurrent 本地做到这一点,但这个对我有用:
import scalaz.Nondeterminism._
import scalaz.std.either.eitherInstance
import scalaz.syntax.bitraverse._
def race[A, B](t1: Task[A], t2: Task[B]): Task[A \/ B] = {
Nondeterminism[Task].choose(t1, t2).map {
_.bimap(_._1, _._2)
}
}
在fs2 - scalaz.concurrent 的继任者 - 是fs2.async#race
【解决方案2】:
虽然使用bimap 确实是正确的,但还有另一种实现方式:
import scalaz.concurrent.Task
import scalaz.Nondeterminism
def firstOf[A, B, C](ta: Task[A], tb: Task[B])(fa: A => C, fb: B => C): Task[C] =
Nondeterminism[Task].chooseAny(ta.map(fa), Seq(tb.map(fb))).map(_._1)
val task1 = Task { Thread.sleep(10000); 4 }
val task2 = Task { Thread.sleep(5000); "test" }
firstOf(task1, task2)(_.toString, identity).unsafePerformSync // test
这里我假设结果的非确定性检索用于获得确切计算时间未知的等效值。因此,该函数将同时执行的转换 fa 和 fb 合并到公共类型。在转换时间难以计算的情况下也很好 - 它选择转换后的第一个结果,例如,在 HTTP 的情况下提取一些请求数据。对于更简单的情况,可以从firstOf 检索并行执行映射的race 函数的变体,如下所示:
def race[A, B](ta: Task[A], tb: Task[B]): Task[A \/ B] = firstOf(ta, tb)(-\/(_), \/-(_))