21

如何在 JavaFX/ScalaFX 应用程序中运行 Akka 演员?

(这是基于第一个答案的问题更新)

是共享相同执行上下文的解决方案吗?意味着拥有基于 JavaFx ExecutorService 的 Actors 调度程序?(运行 UI 操作代码的那个)

这是否意味着一个代理将代表 UI 并能够对其进行操作?我的意思是因为下面建议如果 UI ExecutorService 上有几个演员,这不意味着在代理之间共享状态(对象是 UI)吗?

2 个参与者可以在不同的执行者服务上进行通信吗?我问这个是因为根据下面的建议,一些代理会在 UI Executor Service 上,而另一些则不在。

最后,为什么按原样使用 akka,它的 Executor 上下文不同并使用 Platform.runLater,可能会对 UI 的性能产生一些影响。我提出了在同一个应用程序上的多个执行器服务的问题:这很糟糕吗?

4

3 回答 3

22
  • 期货

将 scala Futures 与 JavaFX 等单线程工具包一起使用的最佳方法是定义一个执行器,允许您在 UI Toolkit 的线程上执行期货或参与者。

Swing 也存在同样的问题,它也需要在 swing 线程上进行更新。Viktor Klang 提出了以下解决方案Swing Execution Context。这里是为 JavaFX 翻译的:

import akka.dispatch.ExecutionContext
import javafx.application.Platform
import java.util.concurrent.Executor

//
object JavaFXExecutionContext {
  implicit val javaFxExecutionContext: ExecutionContext = ExecutionContext.fromExecutor(new Executor {
  def execute(command: Runnable): Unit = Platform.runLater(command)
  })
}

你会像这样使用它:

// import the default ec
import scala.concurrent.ExecutionContext.Implicits.global
// define the JavaFX ec so we can use it explicitly
val fxec = JavaFXExecutionContext.javaFxExecutionContext
future {
  // some asynchronous computation, running on the default
  // ForkJoin ExecutionContext because no ec is passed
  // explicitly
}.map(result => {
  // update JavaFX components from result
  // This will run in the JavaFX thread.
  // Check Platform.isFxApplicationThread() to be sure!
})(fxec)

只要与 JavaFX 组件交互的步骤都在 JavaFX ExecutionContext 上运行,future 的管道可能非常复杂。

注意:是否将 ForkJoin ec 设为默认值并显式传递 JavaFX ec 取决于您,反之亦然。将 JavaFX ec 作为默认设置以防止错误并标记可以使用 ForkJoin ec 显式异步运行的部分可能是一个好主意。

  • 演员

为了将基于 Actor 的系统与单线程 UI 工具包集成,还有一个解决方案。请参阅摇摆演员。您所要做的就是更换

SwingUtilities.invokeLater(command)

Platform.runLater(command)

你可以走了!

  • 什么时候用哪个

如果您有一个大型 UI 应用程序,并且只想分离一些异步操作(加载文件或进行一些计算),那么基于期货的方法可能更可取。但请注意不要与在默认执行上下文上异步运行的期货中的 JavaFX 组件进行任何交互(既不读取也不写入)。

如果您有一个基于actor的大型系统并且只想将UI附加到某些部分,那么在JavaFX线程上运行一些actor可能更可取。YMMV。

于 2013-12-30T09:44:50.120 回答
6

在 JavaFX 中使用多线程时需要考虑以下几点:

  • 任何最终触及场景图的代码(例如,通过更新绑定到控件的数据)都必须包装在Platform.runLater. 如果您使用 JavaFX 中的内置多线程 API(即TaskService),这将自动完成,但如果您使用任何其他多线程实用程序,您必须自己完成。

  • 您的多线程实用程序(即 Akka)必须(我认为)以某种方式被告知要为 JavaFX 事件线程留出一些空间。如果您查看Service的源代码,您会发现它们在配置执行程序时非常小心。我不确定这方面的细节,但是当我尝试将 Scala 的Futures 与 JavaFX 一起使用时,我观察到使用 default 时 UI 中出现了一些无响应,ExecutionContext当我使用基于Service实现的自定义时消失了。

ScalaFX(或据我所知的任何其他工具包)不支持以让您忘记上述两点的方式使用 Scala Futures 或 Akka,但研究起来肯定会很有趣。

于 2013-12-29T21:53:22.720 回答
6

是关于可以在 Swing 或 JavaFX 线程上运行的 akka 演员的要点。它是基于Rüdiger 的回答的 Victor Klang 的Swing Actors的方便、可复制粘贴的扩展。

于 2014-02-13T10:52:52.107 回答