多线程scala中长进程的惯用超时

时间:2012-09-06 03:58:24

标签: multithreading scala concurrency functional-programming

所以,我在stackoverflow上看到一些关于以某种方式询问如何“杀死”未来的问题,而不是弃用的Thread.stop()。我看到答案解释了为什么不可能,但没有解决类似问题的替代机制。

例如:Practical use of futures? Ie, how to kill them?

我意识到未来不能被“杀死”。

我知道如何以Java方式执行此操作:将任务分解为较小的睡眠,并在定期检查的线程类中具有一些“volatile boolean isStillRunning”。如果我通过更新此值取消了该线程,则该线程退出。这涉及“共享状态”(isStillRunning var),如果我在Scala中做同样的事情,它似乎不会非常“有用”。

在惯用功能标量中解​​决此类问题的正确方法是什么?有一个相当简洁的方法吗?我应该恢复“正常”线程和易失性标志吗?我应该以与Java关键字相同的方式使用@volatile吗?

2 个答案:

答案 0 :(得分:1)

是的,它看起来和Java一样。

对于测试装置,测试可能会挂起或运行时间过长,我会使用承诺来测试失败(出于任何原因)。例如,超时监视器可以“取消”测试运行器(中断线程并比较并设置一个标志),然后完成失败的承诺。或者测试准备可能会导致配置错误的测试失败。或者,测试运行并产生结果。在更高的层次上,测试台只能看到未来及其价值。

与Java不同的是你撰写期货的选择。

val all = Future.traverse(tests)(test => {
  val toKeep = promise[Result]    // promise to keep, or fail by monitor
  val f = for (w <- feed(prepare(test, toKeep))) yield {
    monitored(w, toKeep) {
      listener.start(w)
      w.runTest()
    }
  }
  f completing consume _
  // strip context
  val g = f map (r => r.copy(context = null))
  (toKeep completeWith g).future
})

答案 1 :(得分:1)

我想我已经找到了解决自己问题的更好方法。我可以向actor发送更高优先级的退出消息,而不是使用volatile变量让操作知道何时死亡。它看起来像这样:

val a = new Actor() { 
  def act():Unit = {
    loop{ react {
      case "Exit" => exit(); return;
      case MyMessage => {
        //this check makes "Exit" a high priority message, if "Exit" 
        //is on the queue, it will be handled before proceeding to 
        //handle the real message.
        receiveWithin(0) {
          case "Exit" => exit(); return
          case TIMEOUT => //don't do anything.
        }
        sender ! "hi!" //reply to sender
      }
    }}
  }
}

a.start()
val f = a !! MyMessage
while( ! f.isSet && a.getState != Actor.State.Terminated ) {
  //will probably return almost immediately unless the Actor was terminated
  //after I checked.
  Futures.awaitAll(100,f)
}
if( a.getState != Actor.State.Terminated ) {
  f() // the future should evaluate to "hi!"
}
a ! "Exit" //stops the actor from processing anymore messages.
           //regardless of if any are still on the queue.
a.getState // terminated

可能有一种更清晰的方式来写这个..但这与我在申请中所做的大致相同。

除非队列中有“退出”消息,否则reactWithin(0)是立即无操作。队列的“退出”消息替换了我将放在线程Java应用程序中的volatile布尔值。