play - 如何用 futures 包装阻塞代码

play - how to wrap a blocking code with futures

我试图了解这两种方法在功能方面的区别。

class MyService (blockService: BlockService){
   def doSomething1(): Future[Boolean] = {
       //do
       //some non blocking
       //stuff
       val result = blockService.block()
       Future.successful(result)
   }

   def doSomething2(): Future[Boolean] = {
       Future{
          //do
          //some non blocking
          //stuff
          blockService.block()
       }
   }
}

据我了解,两者之间的区别在于哪个线程是将被阻塞的实际线程。

所以如果有一个线程:thread_1执行something1,thread_1将被阻塞,而如果thread_1执行something2一个新线程将 运行 它 - thread_2,并且 thread_2 是要被阻止的线程。

这是真的吗?

如果是这样,那么就没有真正的首选方式来编写这段代码?如果我不关心哪个线程最终会被阻塞,那么最终的结果都是一样的。 dosomething1 似乎是编写此代码的一种奇怪方式,我会选择 dosomething2

有道理吗?

你是对的。我看不出 doSomething1 有什么意义。它只是使调用者的接口复杂化,同时没有提供异步 API.

的好处

如果您在第二种方法中使用不同的 execution contexts,则此方法很有意义。

例如,有一个用于响应请求,另一个用于阻止请求。 因此,您将使用正常的 playExecutionContext 来保持您的应用程序 运行 并在不同的操作中回答和分开 blocking 操作。

def doSomething2(): Future[Boolean] = Future{ 
    blocking { blockService.block() }
}( mySpecialExecutionContextForBlockingOperations )

更多信息:http://docs.scala-lang.org/overviews/core/futures.html#blocking

是的,doSomething1doSomething2 会阻塞不同的线程,但根据您的情况,这是一个重要的决定。

正如@AndreasNeumann 所说,您可以在 doSomething2 中有不同的执行上下文。假设主执行上下文是从您的用户接收 HTTP 请求的上下文。在此上下文中阻塞线程是不好的,因为您可以轻松耗尽执行上下文并影响与 doSomething.

无关的请求

Play docs 对阻塞代码可能出现的问题有更好的解释:

If you plan to write blocking IO code, or code that could potentially do a lot of CPU intensive work, you need to know exactly which thread pool is bearing that workload, and you need to tune it accordingly. Doing blocking IO without taking this into account is likely to result in very poor performance from Play framework, for example, you may see only a few requests per second being handled, while CPU usage sits at 5%. In comparison, benchmarks on typical development hardware (eg, a MacBook Pro) have shown Play to be able to handle workloads in the hundreds or even thousands of requests per second without a sweat when tuned correctly.

在您的例子中,这两种方法都是使用 Play 默认线程池执行的。我建议您查看 recommended best practices and see if you need a different execution context or not. I also suggest you to read Akka docs about Dispatchers and Futures 以更好地了解执行 Futures 和 blocking/non-blocking 代码的内容。

BlockService是否处理阻塞操作?
通常,使用 blocking ,正如@Andreas 提醒的那样,使阻塞操作进入另一个线程是有意义的。