我正在尝试将 Cats Effect 集成到 ScalaFX 桌面应用程序中,但在执行任务时遇到问题。我想运行后台线程/光纤来在显示窗口时对其进行初始化。我认为我正在做的是:
我尝试了一些解决方案,例如调用 SupervisorIO.evalOn() 而不是下面的简单调用。我尝试在 Supervisor#supervise 创建的线程上调用“join”来尝试强制它执行,但没有任何反应。
我将应用程序简化为如下所示(FXML 只是一个 BorderPane 和一个 Label,它配置控制器类;我认为您不需要看到它):
object CatsTest extends IOApp.Simple {
override def run: IO[Unit] = {
IO.blocking {
Application.launch(classOf[CatsTestMain])
}
}
}
class CatsTestMain extends Application {
override def start(primaryStage: Stage): Unit = {
val screen = getClass.getResource("/main-screen.fxml")
val loader = new FXMLLoader()
loader.setLocation(screen)
val root: Parent = loader.load[javafx.scene.Parent]
val controller = loader.getController[MainController]()
primaryStage.setScene(new Scene(new javafx.scene.Scene(root)))
primaryStage.show()
}
}
class MainController extends Initializable {
override def initializable(location: URL, resources: ju.ResourceBundle): Unit = {
println("in controller")
val supervisor = Supervisor[IO](await=true)
supervisor.use { supervisor =>
supervisor.supervise(IO.println("Hello"))
}
}
}
我不知道是否需要封送回原始线程才能使用 Cats 的资源,或者问题是什么。我是 Cats Effect 的新手,这是我一段时间以来编写的第一个不必然使用 Akka/Pekko 的应用程序,所以这似乎是学习它的好方法,但我忍不住我认为我制造的问题比我解决的问题还要多,而不仅仅是使用 Future 对象。
这里有两个问题:
第一个也是最重要的一个是
supervisor.use
返回一个IO
,这只是计算的描述,仅此而已。它需要显式地运行或与其他 IOs
一起排序。这是编写cats-effect应用程序所需的基础知识,IO
只是描述、值,而不是正在运行的计算的处理程序;与Future
Dispatcher
,而不是 Supervisor
: https://typelevel.org/cats-effect/api/3.x/cats/effect/std/Dispatcher.html 为您提供 unsafeRunAndForget
以发送 IO
在后台运行。
其次,您对生命周期的管理不善。您不想为每个
Dispatcher
创建和销毁一个 IO
来执行。理想情况下,MainController
应该收到一个已经分配的Dispatcher
,并且其他东西必须确保它在不再需要时正确关闭。
第三,如果您计划运行的
IOs
会影响界面,则需要在JavaFX的适当线程上运行。
所以这似乎是学习它的好方法
就我个人而言,我不同意。
IO
更适合必须处理并发的 Web 服务器。话虽如此。在过去的几年里,很多人都建造了类似的东西。您可以在 Discord 服务器中寻求建议和资源。