在 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?(这样,至少代码的可读性会高得多)


答案 1

我建议您设置自己的上下文,并使用 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
        }
      }
    }
  }
}

然后在你的控制器中,使用Play 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()));
}

这样,您的 Play 应用仍将处理执行上下文中的短期请求,并且阻塞/CPU 密集型请求将在 中运行。default-dispatchermy-context

我为你做了一个非常简短的例子来演示这一点,在github上查看它。


答案 2

推荐