我有一个简单的猫效应应用程序,它从作为参数给出的URL下载网站。在下载过程中,APP应该会通过在控制台上写点(.
)来显示“加载栏”。我通过对两个*iOS进行“竞争”来实现它,其中一个用于下载另一个用于显示圆点。
这是scastie上的整个应用程序。
最重要的部分在这里:
def loader(): IO[Unit] = for {
_ <- console.putStr(".")
_ <- timer.sleep(Duration(50, MILLISECONDS)) *> loader()
} yield {}
def download(url: String): IO[String] = IO.delay(Source.fromURL(url)).map(_.mkString)
def run(args: List[String]): IO[Unit] = {
args.headOption match {
case Some(url) =>
for {
content <- IO.race(download(url), loader()).map(_.left.get)
_ <- console.putStrLn() *> console.putStrLn(s"Downloaded site from $url. Size of downloaded content is ${content.length}.")
} yield {}
case None => console.putStrLn("Pass url as argument.")
}
}
一切都按照我的预期运行,当我运行它时,我得到:
.已从https://www.scala-lang.org下载站点。下载内容的大小为47738。
唯一的问题是,这款应用永远不会退出。
据我所知,加载器IO被正确取消。我甚至可以添加这样的内容:
urlLoader.run(args) *> console.putStrLn("???") *> IO(ExitCode.Success)
并显示???
。
同样,当我删除RACE时,应用程序可以正确退出。
所以我的问题是,我如何解决这个问题,并让我的应用程序在结束时退出?
2条答案
按热度按时间lyr7nygr1#
继续我上面的评论:问题是您的
ScheduledExecutorService
有阻止JVM退出的线程,即使您的计时器的任务已经取消。有几种方法可以解决此问题:IO(ExitCode.Success)
之前添加IO(ses.shutdown())
。newScheduledThreadPool
。IOApp
内部使用免费获得的timer: Timer
。其中最后一个几乎肯定是正确的选择--使用
IOApp
提供的计时器(和ContextShift
)将为该行为和其他行为提供合理的缺省值。roejwanj2#
您还可以使用如下代码的Scala Futures来防止JVM提前退出: