scala 使用来自猫的比赛效果阻止应用程序退出

6ojccjat  于 2022-11-09  发布在  Scala
关注(0)|答案(2)|浏览(146)

我有一个简单的猫效应应用程序,它从作为参数给出的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时,应用程序可以正确退出。
所以我的问题是,我如何解决这个问题,并让我的应用程序在结束时退出?

lyr7nygr

lyr7nygr1#

继续我上面的评论:问题是您的ScheduledExecutorService有阻止JVM退出的线程,即使您的计时器的任务已经取消。有几种方法可以解决此问题:

  • IO(ExitCode.Success)之前添加IO(ses.shutdown())
  • 使用守护其线程的线程工厂调用newScheduledThreadPool
  • IOApp内部使用免费获得的timer: Timer

其中最后一个几乎肯定是正确的选择--使用IOApp提供的计时器(和ContextShift)将为该行为和其他行为提供合理的缺省值。

roejwanj

roejwanj2#

您还可以使用如下代码的Scala Futures来防止JVM提前退出:

import scala.concurrent.{Await, Future}
import scala.concurrent.duration.Duration

Await.ready(Future.never, Duration.Inf)

相关问题