2016-02-20 27 views
3

我想了解两种方法之间的区别,在功能方面。玩 - 如何包装与期货的阻止代码

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

有意义吗?

回答

2

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

正如@AndreasNeumann所说,您可以在doSomething2中拥有不同的执行上下文。假设主执行上下文是接收来自用户的HTTP请求的执行上下文。在这种情况下阻止线程是不好的,因为您可以轻松地使用与doSomething无关的执行上下文和影响请求。

Play docs有关于可能存在的问题具有阻止代码更好的解释:

如果你打算写阻塞的IO代码,或代码,可能做了很多的CPU密集型的工作,你需要知道确切地说哪个线程池负载该工作负载,并且您需要相应地调整它。 阻止IO而没有考虑到这一点很可能会导致Play框架的性能非常差,例如,您可能会看到每秒只处理几个请求,而CPU使用率为5%。相比之下,典型开发硬件(例如,MacBook Pro)的基准测试表明,Play能够在正确调整的情况下,以每秒几百甚至几千次请求的速度处理工作负载,而不会出汗。

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

1

你是对的。我在doSomething1中看不到一点。它只是简化了调用者的接口,而没有提供异步API的好处。

2

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

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

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

对于一个小的更多信息:http://docs.scala-lang.org/overviews/core/futures.html#blocking

+0

是的,如果我使用2个不同的执行上下文,它是有意义的,但如果不是,这真的意味着什么,对吧? – Tomer

0

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