DynamicVariable无法使用Future

时间:2018-03-02 15:13:30

标签: scala

以下代码:

import scala.concurrent.{Await, Future}
import scala.concurrent.duration.Duration
import scala.util.DynamicVariable
import scala.concurrent.ExecutionContext.Implicits.global

object Main {
  def main(args: Array[String]) = {
    val a = new DynamicVariable(1)
    a.withValue(2) {
      println(a.value)
      Await.result(Future(println(a.value)), Duration.Inf)
    }
  }
}

正在打印:

2
1

但DynamicVariable依赖于InheritableThreadLocal,其在doc:

中说明
  

此类扩展ThreadLocal以提供继承   从父线程到子线程的值:当子线程是   创建后,子进程将接收所有可继承的初始值   父对象具有值的线程局部变量。

这是否意味着InheritableThreadLocal实际上无效?

3 个答案:

答案 0 :(得分:3)

可能我不对,但在我的例子中,我认为在2个线程之间没有父/子关系。

运行Future的线程是导入的global执行上下文中的一个线程。我认为这个执行上下文是在withValue的第二个参数中的thunk开始执行之前创建的。

因此,您提供的文档中的摘录可能不适用于此情况。

如果我错了,请纠正我,因为我也想更好地理解动态变量概念。

答案 1 :(得分:1)

另一个猜测:

TL; DR:Future.apply{...}不生成子线程,它适用于从隐式执行上下文获取的任何线程,在本例中为global

您的情况会发生什么:

  • 您可以使用初始值1
  • 创建动态变量a
  • 您的maina.withValue(2) { println(a.value)在某个线程T1上执行,该线程现在有a.value堆栈[1, 2]
  • 当您致电Future.apply{println(a.value)}时,您的global执行上下文发生,为您提供另一个堆栈T2的{​​{1}}帖子。
  • 您从[1]获得输出2,从T1
  • 获得1

Scastie /我的轻量级设置会发生什么:

  • 创建堆栈为T2的动态变量a
  • [1]在某个线程a.withValue(2) { println(a.value); ... }上运行,该线程现在具有堆栈T1
  • 由于某种原因我的[1, 2]执行上下文在同一个帖子上运行global Future.apply
  • 因此,T1从同一个帖子Future.apply{println(a.value)}
  • 的堆栈2顶部获取值[1,2]
  • 我得到输出“2 2”

总结:

  • 如果线程“丰富”并且您碰巧从执行上下文中获得了不同的线程T1T1,则会得到输出“2 1”。
  • 如果线程“稀缺”(如在线Scastie解释器)并且您恰好在已经运行T2的{​​{1}}中获得相同的T1,那么您将得到“2 2"

这看起来有道理吗?

答案 2 :(得分:1)

以下是使事情有效的文章:
http://stevenskelton.ca/threadlocal-variables-scala-futures/

基本上我们需要实现自定义ForkJoinPool,我们复制DynamicVariables的值。这不是很好的解决方法,但它确实有效。

你们的评论和答案都是正确的 感谢