阻止未来有什么意义吗?
Is there any point in blocking for a future?
假设我有一个应用程序处理很多请求。其中一个请求需要一段时间才能完成。我有以下代码:
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
import scala.concurrent.Await
import scala.concurrent.Future
def longReq(data:String):String = {
val respFuture = Future{
// some code that computes resp but takes a long time
// can my application process other requests during this time?
resp = ??? // time-consuming step
}
Await.result(respFuture, 2 minutes)
}
如果我根本不使用 futures,应用程序将被阻塞,直到 resp
被计算,并且在此期间无法并行处理其他请求。但是,如果我使用 futures 然后使用 Await
阻塞 resp
,应用程序是否能够在计算 resp
时并行处理其他请求?
在您的特定示例中,假设 longReq
被请求循环连续调用,答案是 不,它无法处理任何其他内容。为此 longReq
将不得不 return 一个未来:
def longReq(data:String): Future[String] = {
Future {
// some code that computes resp but takes a long time
// can my application process other requests during this time?
resp = ??? // time-consuming step
}
}
当然,这只是将您可能使用 Await.result
的原因进一步推向了底线。
使用Future
的目的是为了避免阻塞,但它是海龟一路向下买入。如果您想使用 Future
,最终接收者必须能够以 异步 方式处理获取结果,即您的请求循环必须有一种方法来捕获以这样的方式调用者,当未来最终完成时,调用者可以被告知结果
让我们假设你的请求循环接收到一个 response
回调的请求对象,然后你会像这样调用 longReq
(假设使用 longReq
那 return一个 Future
):
def asyncCall(request: Request): Unit = {
longReq(request.data).map( result => request.response(result) )
}
最常见的使用流程的场景是 HTTP 或其他服务器,其中同步 Request => Response
周期具有 async 等价于 Request => Future[Response]
,几乎任何现代服务器框架都提供(Play、Finatra、Scalatra 等)
什么时候使用Await.result
一种情况下,使用 Await.result
可能是合理的,如果你有一堆 Future
并且愿意在全部完成时阻止(假设使用 longReq
那 return 是 Future
):
val futures = allData.map(longReq)) // List[Future[String]]
val combined = Future.sequence(futures) // Future[List[String]]
val responses = Await.result(combined, 10.seconds) // List[String]
当然,combined
是一个 Future
,map
并异步处理结果会更好
假设我有一个应用程序处理很多请求。其中一个请求需要一段时间才能完成。我有以下代码:
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
import scala.concurrent.Await
import scala.concurrent.Future
def longReq(data:String):String = {
val respFuture = Future{
// some code that computes resp but takes a long time
// can my application process other requests during this time?
resp = ??? // time-consuming step
}
Await.result(respFuture, 2 minutes)
}
如果我根本不使用 futures,应用程序将被阻塞,直到 resp
被计算,并且在此期间无法并行处理其他请求。但是,如果我使用 futures 然后使用 Await
阻塞 resp
,应用程序是否能够在计算 resp
时并行处理其他请求?
在您的特定示例中,假设 longReq
被请求循环连续调用,答案是 不,它无法处理任何其他内容。为此 longReq
将不得不 return 一个未来:
def longReq(data:String): Future[String] = {
Future {
// some code that computes resp but takes a long time
// can my application process other requests during this time?
resp = ??? // time-consuming step
}
}
当然,这只是将您可能使用 Await.result
的原因进一步推向了底线。
使用Future
的目的是为了避免阻塞,但它是海龟一路向下买入。如果您想使用 Future
,最终接收者必须能够以 异步 方式处理获取结果,即您的请求循环必须有一种方法来捕获以这样的方式调用者,当未来最终完成时,调用者可以被告知结果
让我们假设你的请求循环接收到一个 response
回调的请求对象,然后你会像这样调用 longReq
(假设使用 longReq
那 return一个 Future
):
def asyncCall(request: Request): Unit = {
longReq(request.data).map( result => request.response(result) )
}
最常见的使用流程的场景是 HTTP 或其他服务器,其中同步 Request => Response
周期具有 async 等价于 Request => Future[Response]
,几乎任何现代服务器框架都提供(Play、Finatra、Scalatra 等)
什么时候使用Await.result
一种情况下,使用 Await.result
可能是合理的,如果你有一堆 Future
并且愿意在全部完成时阻止(假设使用 longReq
那 return 是 Future
):
val futures = allData.map(longReq)) // List[Future[String]]
val combined = Future.sequence(futures) // Future[List[String]]
val responses = Await.result(combined, 10.seconds) // List[String]
当然,combined
是一个 Future
,map
并异步处理结果会更好