当 Task 从不同的词法范围引用时,Monix TaskLocal 似乎没有反映 bind() 调用的值

Monix TaskLocal does not seem to reflect values from bind() call when referenced by Task by from different lexical scope

我有一段代码,它是对 ScalaDoc 中为 TaskLocal 给出的代码片段稍作修改 [原文在这里:https://monix.io/api/3.0/monix/eval/TaskLocal.html].

我的代码只是将内联任务(在 for 理解内)替换为对定义在外部的任务的引用 的理解范围。不幸的是,当我的任务运行时,它看不到绑定,而是看到原始值 (0)。 我希望我稍微修改过的代码(如下)会产生与 ScalaDoc 中的代码片段相同的结果。但没想到,我 得到 "value3: 4",而不是 value3: 200。我对 tlocal 的引用似乎得到了那个 threadlocal-ish 变量的不同 'version' 这是默认设置,对绑定一无所知。

代码

class MonixTests extends FlatSpecLike with Matchers {

  "TaskLocal" should "not make me sad " in {
    val tlocal: Task[TaskLocal[Int]] = TaskLocal(0)

    val readTask: Task[Int] =
      tlocal.flatMap {
        taskLocal: TaskLocal[Int] =>
          taskLocal.read.map{ i => i  * 2 }
      }


    val task: Task[Unit] =
      for {
        local <- tlocal
        value1 <- local.read // value1 == 0
        _ <- local.write(100)
        value2 <- local.read // value2 == 100
        value3 <- local.bind(200)(readTask)
        value4 <- local.read // value4 == 100
        _ <- local.clear
        value5 <- local.read // value5 == 0
      } yield {
        // Should print 0, 100, 400, 100, 0 -- but value3 is not 400, but 4
        println("value1: " + value1)
        println("value2: " + value2)
        println("value3: " + value3)
        println("value4: " + value4)
        println("value5: " + value5)
      }

    import monix.execution.Scheduler.Implicits.global
    implicit val opts = Task.defaultOptions.enableLocalContextPropagation
    task.runToFutureOpt

    println("    TRY AGAIN a slightly different way, but no success ;^( ")

    val task3: Task[Unit] =
      for {
        local <- tlocal
        value1 <- local.read // value1 == 0
        _ <- local.write(100)
        value2 <- local.read // value2 == 100
        value3 <- local.bind(200)(readTask)
        value44 <-  local.bind(200) (
          tlocal.flatMap {
            taskLocal: TaskLocal[Int] =>
              taskLocal.read.map{i => i  *  2}
          }
        )
        _ <- local.clear
        value5 <- local.read // value5 == 0
      } yield {
        // Should print 0, 100, 400, 100, 0 -- but value3 is not 400, but 4
        println("value1: " + value1)
        println("value2: " + value2)
        println("value3: " + value3)
        println("value4: " + value44)
        println("value5: " + value5)
      }

    task3.runToFutureOpt
  }

理由:

我想这样做的原因是因为我想将一个值绑定到我的本地线程,然后创建一个任务映射链,其中 其中一些任务拉取了本地线程的当前值,据我所知,TaskLocal 是 'fronted'。而且,只是 需要明确的是,其中一些任务是在我的代码库中的其他 类 中定义的,没有内联在任何特定的理解范围内。

谢谢! /克里斯

我现在很高兴,因为我知道如何或多或少地做我想做的事情。 下面的解决方案直接使用 "Local" 而不是 TaskLocal。但它具有预期的效果 绑定值 (200) 在引用线程局部变量 'tlocal'.

的代码块中可见

我真的不需要在 'Task context' 中做任何事情,所以这让我走上了正确的轨道。

  "TaskLocal" should "not make me sad today" in {
    import monix.execution.misc.Local

    val tlocal = Local(0)

    def doubleTlocal: Int = {tlocal.get * 2}

    val value1 = tlocal.get // value1 == 0
    tlocal.update(100)
    val value2 = tlocal.get // value2 == 100
    val value3 = tlocal.bind(200)(doubleTlocal)
    val value4 = tlocal.get // value4 == 100

     tlocal.clear
    val value5 = tlocal.get // value5 == 0

    println("value1: " + value1)
    println("value2: " + value2)
    println("value3: " + value3)
    println("value4: " + value4)
    println("value5: " + value5)
  }