【问题标题】:Using race from cats-effect prevents app from exiting使用 cat-effect 中的种族可防止应用退出
【发布时间】:2019-06-21 20:03:35
【问题描述】:

我有一个简单的猫效应应用程序,它从作为参数给出的 URL 下载站点。在下载应用程序期间,应该通过将点 (.) 写入控制台来显示“加载栏”。我通过对两个 IOs 进行 race 来实现它,一个用于下载另一个用于显示点。

这是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。

唯一的问题是应用永远不会退出。

据我检查 loader IO 被正确取消。我什至可以添加这样的内容:

urlLoader.run(args) *> console.putStrLn("???") *> IO(ExitCode.Success)

??? 会显示出来。

此外,当我删除 race 时,应用程序会正确退出。

所以我的问题是如何解决这个问题并让我的应用程序最终退出?

【问题讨论】:

  • 您没有使用IOApp 提供的Timer 有什么原因吗?乍一看,问题在于您没有关闭调度程序,如果您使用的是内置计时器,则不必担心。
  • 我错过了 IOApp 已经介绍了 Timer。我从there 获取了我的实现。不是它像魅力一样,谢谢!

标签: scala scala-cats cats-effect


【解决方案1】:

跟进我上面的评论:问题是您的ScheduledExecutorService 运行的线程会阻止 JVM 退出,即使您的计时器任务已被取消。有几种方法可以解决这个问题:

  • IO(ExitCode.Success) 之前添加IO(ses.shutdown())
  • 调用 newScheduledThreadPool 并使用一个线程工厂来守护其线程。
  • 使用您在IOApp 中免费获得的timer: Timer

其中最后一个几乎绝对是正确的选择——使用IOApp 提供的计时器(和ContextShift)将为您提供此行为和其他行为的合理默认值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-27
    • 1970-01-01
    • 2017-02-11
    • 1970-01-01
    相关资源
    最近更新 更多