Scala 如何将java.util.concurrent.Future包装到Akka Future中?
在PlayFramework2.0.1(Scala)应用程序中,我们使用一个web服务客户端库,它返回Scala 如何将java.util.concurrent.Future包装到Akka Future中?,scala,playframework-2.0,akka,future,Scala,Playframework 2.0,Akka,Future,在PlayFramework2.0.1(Scala)应用程序中,我们使用一个web服务客户端库,它返回java.util.concurrent.Future作为响应 我们希望将j.u.c.Future封装在akka.dispatch.Future中,而不是在get()调用中阻止Play应用程序,这样我们就可以轻松地使用Play框架的AsyncResult处理 以前有没有人这样做过,或者有库或示例代码 更新:我们找到的最接近的东西是谷歌小组讨论: …如果你所拥有的只是一个简单的j.u.c.未来,
java.util.concurrent.Future
作为响应
我们希望将j.u.c.Future
封装在akka.dispatch.Future
中,而不是在get()
调用中阻止Play应用程序,这样我们就可以轻松地使用Play框架的AsyncResult
处理
以前有没有人这样做过,或者有库或示例代码
更新:我们找到的最接近的东西是谷歌小组讨论: …如果你所拥有的只是一个简单的j.u.c.未来,那么创建一个非阻塞解决方案的最佳方法就是接受j.u.c.未来和一个承诺,并将它们交给运行轮询循环的某个线程,当它完成时,该线程将使用未来的结果完成承诺
有人有这样的例子吗?@Viktor Klang:我们知道
j.u.c.Future
是一个令人憎恶的东西。但这正是我们从目前必须接受的软件中得到的
到目前为止,这是我们一起破解的:
def wrapJavaFutureInAkkaFuture[T](javaFuture: java.util.concurrent.Future[T], maybeTimeout: Option[Duration] = None)(implicit system: ActorSystem): akka.dispatch.Future[T] = {
val promise = new akka.dispatch.DefaultPromise[T]
pollJavaFutureUntilDoneOrCancelled(javaFuture, promise, maybeTimeout.map(_.fromNow))
promise
}
换句话说,创建一个与j.u.c.Future
相对应的单独的AkkaPromise
(未来的写入端),启动回调pollJavaFutureUnteldone或Cancelled
,通过轮询“憎恶”来更新承诺,并将承诺返回给调用者
那么,我们如何根据j.u.c.的未来状况“投票”更新Akka承诺
def pollJavaFutureUntilDoneOrCancelled[T](javaFuture: java.util.concurrent.Future[T], promise: akka.dispatch.Promise[T], maybeDeadline: Option[Deadline] = None)(implicit system: ActorSystem) {
if (maybeDeadline.exists(_.isOverdue)) javaFuture.cancel(true);
if (javaFuture.isDone || javaFuture.isCancelled) {
promise.complete(allCatch either { javaFuture.get })
} else {
Play.maybeApplication.foreach { implicit app =>
system.scheduler.scheduleOnce(50 milliseconds) {
pollJavaFutureUntilDoneOrCancelled(javaFuture, promise, maybeDeadline)
}
}
}
}
这是我在问题中提到的谷歌集团讨论中暗示的一种尝试。它使用Akka调度程序每50毫秒回拨一次,检查j.u.c.未来是否完成或取消。无论何时,它都会用完成状态更新Akka承诺
@Victor Klang等人:
这是最佳实践吗?你知道更好的方法吗?我们是否错过了一个我们应该知道的缺点
谢谢您的帮助。您应该将akka.dispatch.Futures.future()
与java.util.concurrent.Callable一起使用:
val akkaFuture: akka.dispatch.Future[String] = akka.dispatch.Futures.future(
new java.util.concurrent.Callable[String] {
def call: String = {
return "scala->" + javaFuture.get
}
}, executionContext)
一个明显的缺点是,在最坏的情况下,这将导致响应的严重延迟。例如,如果您有默认设置,并且您的未来在检查后1毫秒完成,则可能会导致大约100毫秒的延迟。不过,这可以通过在配置中设置“调度程序.勾选持续时间”设置来进行调整。@drexin true,但任何基于轮询的解决方案都会存在勾选持续时间和轮询频率的权衡,对吗?当然,但当你问到缺点时,我只想告诉你,它不仅取决于scheduleOnce
调用的delay参数,还取决于akka配置中的设置。如果你能忍受一个延迟,这应该是一个可用的解决方案。这实际上会导致超过必要的线程数量,其中一个阻塞,这并不比简单地在主线程上调用javaFuture.get好多少。除了绝对需要组件兼容性的极端情况外,引入akka future在这里是没有好处的。