Scalaz任务首先完成

时间:2017-06-30 14:47:24

标签: scala functional-programming scalaz

我有两个scalaz.concurrent.Task正在向不同的服务器执行HTTP请求。

我想以类似于Future.firstCompletedOf的方式编写它们,即:并行运行它们并获得第一个成功完成的结果。

不幸的是Task.gatherUnordered不符合我的要求,因为它会在返回结果之前完成每个任务的完成。

2 个答案:

答案 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

这里我假设结果的非确定性检索用于获得精确计算时间未知的等效值。因此,该函数将同时执行的转换fafb合并到公共类型中。在转换时间难以计算的情况下也很好 - 它在转换后选择第一个结果,例如,在HTTP的情况下提取一些请求数据。对于更简单的情况,从race检索并行执行映射的firstOf函数变体,如下所示:

def race[A, B](ta: Task[A], tb: Task[B]): Task[A \/ B] = firstOf(ta, tb)(-\/(_), \/-(_))