【问题标题】:Dynamic variables and promises动态变量和承诺
【发布时间】:2019-08-20 21:29:11
【问题描述】:

似乎动态变量并不总是能够在线程中的子例程调用中存活:

sub foo($x, &y = &infix:<+>) {
  my &*z = &y;
  bar($x);
}

sub bar ($x) {
    say &*z($x,$x);

    my $promise = start { bar($x-1) if $x > 0 }
    await $promise;

    # bar($x-1) if $x > 0    # <-- provides the expected result: 6, 4, 2, 0
}
foo(3); # 6, 4, Dynamic variable &*z not found

使用更全局范围的变量也可以,所以并不是所有变量都丢失了——它似乎是动态特性所特有的:

our &b;

sub foo($a, &c = &infix:<+>) {
  &b = &c;
  bar($a);
}

sub bar ($a) {
    say &b($a,$a);
    my $promise = start { bar($a-1) if $a > 0 }
    await $promise;
}

foo(3); # 6, 4, 2, 0

一旦在foo() 中设置了变量,就可以在bar() 中毫无问题地读取它。但是当 bar() 从 promise 内部调用时,&amp;*z 的值不是在第一层递归而是在第二层消失。

我感觉到了一个错误,但也许我在递归/动态变量/线程之间做了一些奇怪的事情,这把事情搞砸了。

【问题讨论】:

    标签: multithreading raku


    【解决方案1】:

    在当前语义下,start 将捕获它被调用的上下文。如果动态变量查找在start 执行的线程的堆栈上失败(来自线程池的线程之一),那么它将回退到查看在调度 start 块时捕获的动态范围。

    在另一个start 块的执行期间创建start 块时,会发生同样的事情。但是,两者之间没有关系,这意味着“外部”start 块捕获的上下文也不会被搜索。虽然有人可能会主张这种情况发生,但这样做似乎可能存在问题。考虑这个例子:

    sub tick($n = 1 --> Nil) {
        start {
            await Promise.in(1);
            say $n;
            tick($n + 1);
        }
    }
    tick();
    sleep;
    

    这是每秒产生一个滴答声的(并非完全惯用的)方式。如果内部start 保留对外部状态状态的引用,以进行动态变量查找,那么该程序将在内存中建立一个长度不断增加的链,这似乎是一种不良行为。

    【讨论】:

    • 很好的答案。这对于为什么会发生是有道理的。我不确定它应该去哪里(无论是在变量中还是在异步的东西中)但是有人(例如我,每当我终于有空闲时间全神贯注于编写/编辑文档时)应该在某个地方提到这一点.谢天谢地,我可以相当简单地解决它,它会留在模块代码领域,没有人可以看到它
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-09-18
    • 2021-02-15
    • 1970-01-01
    • 2017-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多