IO应用程序未关闭执行的原因是什么?

发布于 2025-02-08 15:03:21 字数 701 浏览 2 评论 0原文

为什么要挂?

import cats.effect.IO
import cats.effect.unsafe.implicits.global
import com.typesafe.config.ConfigFactory
import io.circe.config.parser
import org.typelevel.log4cats._
import org.typelevel.log4cats.slf4j._

object ItsElenApp extends App:

  private val logger: SelfAwareStructuredLogger[IO] = LoggerFactory[IO].getLogger

  val ops = for
    _ <- logger.info("aa")
    _ <- IO(println("bcc"))
    _ <- logger.error("bb")
  yield ()

  ops.unsafeRunSync()

  println("end")

它打印:

INFO 2022-06-19 11:56:25,303 ItsElenApp - aa
bcc

保持运行。是log4cats库,还是我以错误的方式使用应用程序对象。还是我必须关闭执行上下文?

Why does this hang?

import cats.effect.IO
import cats.effect.unsafe.implicits.global
import com.typesafe.config.ConfigFactory
import io.circe.config.parser
import org.typelevel.log4cats._
import org.typelevel.log4cats.slf4j._

object ItsElenApp extends App:

  private val logger: SelfAwareStructuredLogger[IO] = LoggerFactory[IO].getLogger

  val ops = for
    _ <- logger.info("aa")
    _ <- IO(println("bcc"))
    _ <- logger.error("bb")
  yield ()

  ops.unsafeRunSync()

  println("end")

It prints:

INFO 2022-06-19 11:56:25,303 ItsElenApp - aa
bcc

and keeps running. Is it the log4cats library, or am I using the App object in a wrong way. Or do I have to close an execution context?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

指尖上的星空 2025-02-15 15:03:21

推荐的运行cats.effect.io基于基于的应用程序的方法是cats.effect.ioapp(或cats.effect.resourceapp):

object MyApp extends IOApp:

  // notice it takes List[String] rather than Array[String]
  def run(args: List[String]): IO[ExitCode] = ...

this would run the application, handle setting up exit code, etc.

另一方面不建议扩展app。为什么?它使用特殊的延迟机制,其中全部(其构造函数)懒惰。这使得初始化更加困难,这就是为什么这种机制被贬低/灰心的原因。如果您不使用IOAPP,最好实施类似的事情:

object MyProgram:

  // Java requires this signature
  def main(args: Array[String]): Unit = ...

在您的情况下看起来像是

object ItsElenApp:

  private val logger: SelfAwareStructuredLogger[IO] = LoggerFactory[IO].getLogger

  def main(args: Array[String]): Unit =
    val ops = for
      _ <- logger.info("aa")
      _ <- IO(println("bcc"))
      _ <- logger.error("bb")
    yield ()

    // IOApp could spare you this
    try
      ops.unsafeRunSync()
    finally
      println("end")
      sys.exit(0)

The recommended way of running cats.effect.IO-based apps is using cats.effect.IOApp (or cats.effect.ResourceApp):

object MyApp extends IOApp:

  // notice it takes List[String] rather than Array[String]
  def run(args: List[String]): IO[ExitCode] = ...

this would run the application, handle setting up exit code, etc. It closes the app when run reaches the end, which might be necessary if the default thread pool is non-daemon. If you don't want to use IOApp you might need to close JVM manually, also taking into consideration that exception might have been thrown on .unsafeRunSync().

Extending App is on the other hand not recommended in general. Why? It uses special Delayed mechanism where the whole body of a class (its constructor) is lazy. This makes it harder to reason about the initialization, which is why this mechanism became deprecated/discouraged. If you are not using IOApp it is better to implement things like:

object MyProgram:

  // Java requires this signature
  def main(args: Array[String]): Unit = ...

which in your case could look like

object ItsElenApp:

  private val logger: SelfAwareStructuredLogger[IO] = LoggerFactory[IO].getLogger

  def main(args: Array[String]): Unit =
    val ops = for
      _ <- logger.info("aa")
      _ <- IO(println("bcc"))
      _ <- logger.error("bb")
    yield ()

    // IOApp could spare you this
    try
      ops.unsafeRunSync()
    finally
      println("end")
      sys.exit(0)
哥,最终变帅啦 2025-02-15 15:03:21

因为Log4Cats的记录功能似乎是异步的。这意味着它们可能会在另一个线程上运行,而不是与其他操作序列。

这意味着主螺纹可能会完成,但是其他线程不断打开并且永不关闭。

如果我使用ops.unsaferuntimed(2.seconds)所有内容都执行并关闭。但是后一个日志线仅在结束时出现。看来记录是某种程度上懒惰的,只有在要求它的情况下才能完成。我不知道。

他们写作,您不应在生产代码中使用

当然,如果您使用ioApp,则一切都会再次正常执行。

但是,如果没有ioApp,您将如何在生产代码中编写此此内容?我认为应该有一种干净的方式告诉log4cats完成操作,返回其异步纤维结果并关闭所有内容。全部手动。

Because log4cats' logging functions seem to be asynchronous. Meaning they might run on a different thread, not in sequence with the other operations.

That means the main thread might finish but the other threads keep being opened and never closing.

If I use ops.unsafeRunTimed(2.seconds) everything executes and closes. But the latter log lines come only at the end of the time. Looks like the logging is somehow lazy and only finishes if it is asked to. I'm not sure.

They write you shouldn't use unsafeRunTimed in production code.

Of course if you use IOApp, everything executes normally again.

But how would you write this in production code, cleanly, nicely without an IOApp? I think there should be a clean way of telling log4cats to finish the operations, return their async fibers results and close everything. All manually.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文