play - 如何用期货

时间:2016-02-20 11:18:01

标签: scala asynchronous playframework future

我试图在功能方面理解两种方法之间的区别。

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()
       }
   }
}

据我所知,2之间的区别在于哪个线程是将被阻止的实际线程。

因此,如果有一个线程:thread_1执行something1,则thread_1将被阻止,而如果thread_1执行something2新线程将运行它 - thread_2,thread_2是那个被封锁的人。

这是真的吗?

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

有意义吗?

4 个答案:

答案 0 :(得分:3)

是的,doSomething1doSomething2会阻止不同的主题,但根据您的情况,这是一个重要的决定。

正如@AndreasNeumann所说,你可以在doSomething2中拥有不同的执行上下文。想象一下,主执行上下文是接收来自用户的HTTP请求的上下文。此上下文中的块线程很糟糕,因为您可以轻松耗尽执行上下文并影响与doSomething无关的请求。

Play docs可以更好地解释阻塞代码可能存在的问题:

  

如果您计划编写阻塞IO代码或可能会执行大量CPU密集型工作的代码,则需要确切知道哪个线程池承载了该工作负载,并且您需要相应地对其进行调整。 在不考虑这一点的情况下阻止IO可能会导致Play框架的性能非常差,例如,您可能会看到每秒只处理少量请求,而CPU使用率则为5%。相比之下,典型开发硬件(例如MacBook Pro)的基准测试表明Play能够在正确调整的情况下,每秒处理数百甚至数千个请求中的工作负载。

在您的情况下,两个方法都是使用Play默认线程池执行的。我建议你看看recommended best practices,看看你是否需要不同的执行环境。我还建议您阅读有关DispatchersFutures的Akka文档,以便更好地了解执行期货的内容以及阻止/非阻止代码。

答案 1 :(得分:2)

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

例如,有一个用于回复请求,另一个用于阻止请求。 因此,您可以使用常规playExecutionContext来保持应用程序的运行和回答,并将blocking操作分开。{/ p>

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

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

答案 2 :(得分:1)

你是对的。我在doSomething1中没有看到一点。它简单地使调用者的接口复杂化,同时不提供异步API的好处。

答案 3 :(得分:0)

BlockService会处理阻止操作吗? 通常,正如@Andreas提醒的那样,使用blocking来阻止对另一个线程的操作是有意义的。