Scala 理解与取消相关的cats.effect.Concurrent

Scala 理解与取消相关的cats.effect.Concurrent,scala,cats-effect,Scala,Cats Effect,鉴于: build.sbt src/main/scala/net/main.scala 注意,大约30秒后,我取消了它 为什么“秒数已完成:未打印: notUncancellable seconds begin: 303055 ^C$ ?不可取消我相信是不言自明的 在《不可癌变》中,你会遇到类似的情况 正如Alexandru Nedelcu所说: fiber.cancel使fiber.join在IO情况下不终止。因此fiber.join将永远不会完成,并且该保证永远不会得到评估的机会 如果你也

鉴于:

build.sbt src/main/scala/net/main.scala 注意,大约30秒后,我取消了它

为什么
“秒数已完成:
未打印:

notUncancellable
seconds begin: 303055
^C$

不可取消
我相信是不言自明的

在《不可癌变》中,你会遇到类似的情况

正如Alexandru Nedelcu所说:

fiber.cancel
使
fiber.join
在IO情况下不终止。因此
fiber.join
将永远不会完成,并且该保证永远不会得到评估的机会

如果你也取消了评估,你可以强制进行评估。在真正的应用程序中,如果你关心
fiber.join的结果,你需要这样做

据我所知,这是一种可能的解释

取消的光纤无法返回成功的值-这是显而易见的。但如果它返回另一个故障的异常…它还将返回一个值,该值可以被视为由光纤计算的值-该值不应返回任何值,因为它已被取消

因此,在这种情况下,整个线程都在等待一个从未到达的值

为了避免这样的陷阱,你可以使用一些不太“低级”的东西,比如
racePair
或类似的东西来避免自己处理这样的问题。你可以阅读Oleg Pyzhcov的一篇短文

package net

import cats.effect._
import cats.implicits._
import java.util.concurrent.TimeUnit
import scala.concurrent.duration._

object App extends IOApp { self: IOApp =>
  override def run(args: List[String]): IO[ExitCode] =
    for {
      _ <- uncancellable
      _ <- notUncancellable
    } yield ExitCode.Success

  private def uncancellable: IO[Unit] = {
    val tick: IO[Unit] = Concurrent[IO].uncancelable(self.timer.sleep(10.seconds))

    for {
      _ <- IO(println("uncancellable"))
      fiber <- Concurrent[IO].start(tick)
      _ <- IO(println("seconds begin: " + FiniteDuration.apply(System.nanoTime(), TimeUnit.NANOSECONDS).toSeconds))
      _ <- fiber.cancel
      _ <- fiber.join
      _ <- IO(println("seconds done : " + FiniteDuration.apply(System.nanoTime(), TimeUnit.NANOSECONDS).toSeconds))
    } yield ()
  }

  private def notUncancellable: IO[Unit] = {
    val tick: IO[Unit] = self.timer.sleep(10.seconds)

    for {
      _ <- IO(println("notUncancellable"))
      fiber <- Concurrent[IO].start(tick)
      _ <- IO(println("seconds begin: " + FiniteDuration.apply(System.nanoTime(), TimeUnit.NANOSECONDS).toSeconds))
      _ <- fiber.cancel
      _ <- fiber.join
      _ <- IO(println("seconds done : " + FiniteDuration.apply(System.nanoTime(), TimeUnit.NANOSECONDS).toSeconds))
    } yield ()
  }
}
sbt:cats-effect-cancellation-question> run
[info] Compiling 1 Scala source to /Users/kevinmeredith/Workspace/cats-effect-cancellation-questions/target/scala-2.13/classes ...
[info] Done compiling.
[info] Packaging /Users/kevinmeredith/Workspace/cats-effect-cancellation-questions/target/scala-2.13/cats-effect-cancellation-question_2.13-0.1.jar ...
[info] Done packaging.
[info] Running net.App 
uncancellable
seconds begin: 303045
seconds done : 303055
notUncancellable
seconds begin: 303055
^C$
notUncancellable
seconds begin: 303055
^C$
  /**
   * Returns a new task that will await for the completion of the
   * underlying fiber, (asynchronously) blocking the current run-loop
   * until that result is available.
   */
  def join: F[A]