我有两个scalaz.concurrent.Task
正在向不同的服务器执行HTTP请求。
我想以类似于Future.firstCompletedOf
的方式编写它们,即:并行运行它们并获得第一个成功完成的结果。
不幸的是Task.gatherUnordered
不符合我的要求,因为它会在返回结果之前完成每个任务的完成。
答案 0 :(得分:1)
Not sure how to do it in scalaz.concurrent
natively, but this one works for me:
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)
}
}
In fs2
- successor of scalaz.concurrent
- it is fs2.async#race
答案 1 :(得分:1)
虽然使用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的情况下提取一些请求数据。对于更简单的情况,从race
检索并行执行映射的firstOf
函数变体,如下所示:
def race[A, B](ta: Task[A], tb: Task[B]): Task[A \/ B] = firstOf(ta, tb)(-\/(_), \/-(_))