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

oo_*_*_oo 13 java multithreading asynchronous playframework-2.0

我的应用程序使用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操作,考虑到这样的操作无论如何都使用相同的线程池这一事实.或者也许最好增加默认的线程池大小,在这种情况下不要打扰async api?(这样至少代码可读性会高得多)

Fra*_*anz 22

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

首先在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
        }
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

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

public static F.Promise<Result> love() {
    ExecutionContext myExecutionContext = Akka.system().dispatchers().lookup("play.akka.actor.my-context");

    F.Promise<Integer> integerPromise = F.Promise.promise(() ->
            LongRunningProcess.run(10000L)
    , myExecutionContext);

    F.Promise<Integer> integerPromise2 = F.Promise.promise(() ->
            LongRunningProcess.run(10000L)
    , myExecutionContext);

    return integerPromise.flatMap(i -> integerPromise2.map(x -> ok()));
}
Run Code Online (Sandbox Code Playgroud)

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

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

  • 很好的答案,我发现这也是正确的做法.我在默认上下文中运行时间/ CPU密集型进程,这导致其他Play Futures出现问题,即Play Web Service API不再有效.将我的密集型流程移动到他们自己的上下文修复了WS请求的问题. (2认同)