在Java中播放框架异步处理和阻止I / O.

我的应用程序使用Play框架来处理REST请求。 我需要在http请求处理程序中执行一些可能持久的阻塞I / O操作。 与此同时,我希望有效地处理一些持久的请求。

如下所述:

http://www.playframework.com/documentation/2.2.0/JavaAsync

持久的操作可以异步运行。 另一方面,如下所述:

http://www.playframework.com/documentation/2.2.x/ThreadPools

Play框架使用相同的默认线程池,其中执行所有应用程序代码。 至少在Java api中,不可能在不同的线程池上运行异步工作。

所以,我的问题是,是否值得以异步方式运行可能阻塞的I / O操作,考虑到这样的操作无论如何都使用相同的线程池这一事实。 或者也许最好增加默认的线程池大小,并且在这种情况下不要打扰异步api? (这样至少代码可读性会高得多)

我建议您使用Plays F.Promise设置自己的上下文并在那里运行阻塞/ cpu密集型操作。 与线程一样,最佳解决方案取决于许多内容,例如内核数量等。

首先在applications.conf设置你的上下文:

 play { akka { akka.loggers = ["akka.event.Logging$DefaultLogger", "akka.event.slf4j.Slf4jLogger"] loglevel = WARNING actor { default-dispatcher = { fork-join-executor { parallelism-min = 1 parallelism-factor = 2 parallelism-max = 6 } } my-context { fork-join-executor { parallelism-min = 1 parallelism-factor = 4 parallelism-max = 16 } } } } } 

然后在你的控制器中,使用Plays Promises(我正在使用Java 8)来使用你的上下文:

 public static F.Promise love() { ExecutionContext myExecutionContext = Akka.system().dispatchers().lookup("play.akka.actor.my-context"); F.Promise integerPromise = F.Promise.promise(() -> LongRunningProcess.run(10000L) , myExecutionContext); F.Promise integerPromise2 = F.Promise.promise(() -> LongRunningProcess.run(10000L) , myExecutionContext); return integerPromise.flatMap(i -> integerPromise2.map(x -> ok())); } 

这样,您的Play应用程序仍将处理default-dispatcher程序执行上下文中的持久请求,并且阻塞/ cpu密集将在my-context运行。

我为你演示了一个非常简短的例子,请在github上查看。