【问题标题】:Play framework async processing and blocking I/O in Java在 Java 中播放框架异步处理和阻塞 I/O
【发布时间】:2014-04-27 11:12:00
【问题描述】:

我的应用程序使用 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? (这样至少代码可读性会高很多)

【问题讨论】:

  • 在单独的线程池上运行持久的操作,或者为每个操作启动单独的线程。
  • @AlexeiKaigorodov:我愿意,但我在 Java api 中没有发现这种可能性。不过,我在 Scala api 中读到了这种可能性。但我现在正在使用 Java。
  • 你没有找到如何通过java API启动线程或线程池?
  • :-) 不,我还没有找到如何使用本机 Play 框架 api 来做到这一点。我可以自己做 - 这是一种解决方案。但它需要有关 Play 本身的较低级别的知识,才能正确执行。并且可能与不同的 Play 助手不兼容,例如动作装饰器等
  • 我不是 Play 专家,但我认为启动一个线程(池)不会有任何害处。但问题是,如何将长时间操作的结果传递回 Play 框架 - 应该使用一些异步机制,而不是在 Play 控制的线程上等待结果。

标签: java multithreading asynchronous playframework-2.0


【解决方案1】:

我建议您设置自己的上下文并使用 Plays F.Promise<A> 在此处运行阻塞/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<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 应用仍将处理 default-dispatcher 执行上下文中的短期请求,而阻塞/cpu 密集型将在 my-context 中运行。

我制作了一个非常简短的示例供您演示,请在 github 上查看。

【讨论】:

  • 好答案,我发现这也是正确的做法。我在默认上下文中运行时间/cpu 密集型进程,这导致其他 Play Futures 出现问题,即 Play Web Service API 不再工作。将我的密集流程转移到他们自己的上下文中解决了 WS 请求的问题。
猜你喜欢
  • 2018-04-06
  • 2015-09-01
  • 1970-01-01
  • 2011-09-16
  • 1970-01-01
  • 2012-05-21
  • 2017-11-14
  • 1970-01-01
相关资源
最近更新 更多