如果另一个任务失败,如何组合两个并行任务来取消一个任务?

时间:2015-10-11 13:30:09

标签: scala concurrency task scalaz

我想用 scalaz.concurrent.Task实现异步处理。我需要一个函数(Task[A], Task[B]) => Task[(A, B)]来返回一个如下工作的新任务:

  • 并行运行Task[A]Task[B]并等待结果;
  • 如果其中一个任务失败,那么取消第二个任务并等待它终止;
  • 返回两个任务的结果。

你将如何实现这样的功能?

2 个答案:

答案 0 :(得分:3)

如上所述,如果您不关心实际停止未失败的计算,可以使用Nondeterminism。例如:

import scalaz._, scalaz.Scalaz._, scalaz.concurrent._

def pairFailSlow[A, B](a: Task[A], b: Task[B]): Task[(A, B)] = a.tuple(b)

def pairFailFast[A, B](a: Task[A], b: Task[B]): Task[(A, B)] =
  Nondeterminism[Task].both(a, b)

val divByZero: Task[Int] = Task(1 / 0)
val waitALongTime: Task[String] = Task {
  Thread.sleep(10000)
  println("foo")
  "foo"
}

然后:

pairFailSlow(divByZero, waitALongTime).run // fails immediately
pairFailSlow(waitALongTime, divByZero).run // hangs while sleeping
pairFailFast(divByZero, waitALongTime).run // fails immediately
pairFailFast(waitALongTime, divByZero).run // fails immediately

除了第一种情况外,waitALongTime中的副作用都会发生。如果您想尝试停止该计算,则需要使用Task' s runAsyncInterruptibly之类的内容。

答案 1 :(得分:2)

java开发人员之间有一个奇怪的概念,你不应该取消并行任务。他们对Thread.stop()进行了授权并将其标记为已弃用。没有Thread.stop()你就无法取消未来。您所能做的就是向未来发送一些信号,或者修改一些共享变量并在将来制作代码以定期检查它。因此,所有提供期货的图书馆都可以建议取消未来的唯一方法:合作做。

我现在面临同样的问题,正在编写我自己的图书馆,可以取消期货。有一些困难,但可以解决。你无法在任意位置调用Thread.stop()。线程可以执行更新共享变量。锁定将被正常调用,但更新可能会在中途停止,例如只更新double值的一半,依此类推。所以我引入了一些锁定。如果线程处于保护状态,那么它现在应该被Thread.stop()杀死,但是发送特定的消息。守卫状态被认为总是很快等待。所有其他时间,在计算过程中,线程可以安全地停止并替换为新线程。

所以,答案是:你不应该想取消期货,否则你就是异教徒,java社区中没有人愿意帮你。你应该定义你自己的执行上下文,它可以杀死线程,你应该编写自己的期货库来运行这个上下文