Await.result还是只是一个简单的电话?

时间:2013-11-24 11:41:59

标签: multithreading scala future

我正在尝试处理futures。这两者之间是否存在重大差异?

//1
import scala.concurrent.Await
import scala.concurrent.Future
import scala.concurrent.duration._

def longRequestToServer(): String = {...}
val future = Future { longRequestToServer() }
val resultAsync = Await.result(future, 60.seconds)

//2 
val resultSync = try {
  longRequestToServer()
} catch {
  case _: Exception => "???"
}

除第一种情况中60 seconds的时间段外。

2 个答案:

答案 0 :(得分:14)

阻止是邪恶的。

在将来阻塞然后等待结果会消耗两个线程而不是一个。

那是邪恶的两倍吗?

这是你想要避免的拦截电话。

(将来,你至少要把它包裹在blocking中,使其成为邪恶的一半。确切的比例实际上是.666邪恶。)

编辑:需要考虑的其他因素是两个版本在关机时可能会有不同的行为。在第一种情况下,未来可以被拒绝。协调这些影响,尤其是多个自定义执行程序和回调,相对微妙且容易出错。 (这是人们更喜欢演员的未来。)

(早期,所有throwable的期货并不完全健壮,因此您可能无法在工作线程上看到错误,但AFAIK已修复。)

答案 1 :(得分:4)

所以这两者之间有两点不同。

第二个是一个标准的非异步调用,你等待返回方法并阻塞当前线程并在之后进行错误处理。

在我看来,第一个是朝着正确方向迈出的一步。你将来开始长期运行的任务并且不会在原始线程上阻塞,但是因为你使用Await.result,你实际上创建了第二个线程,然后使用比之前的更多资源阻止第一个线程结束,但是你也没有做任何错误处理。

您应该做的是使用回调:http://docs.scala-lang.org/overviews/core/futures.html

val future = Future { longRequestToServer() }
future onSuccess {
  case result => doSomething(result)
}
future onFailure {
  case t => println("An error has occured: " + t.getMessage)
}

因此具有不使用长背景计算阻塞线程并进行错误管理的优点。

当然有时候使用Await.result是明智的,但大多数时候你可以编写一个带回调的非阻塞变体。