use*_*601 6 multithreading perl6 raku
似乎动态变量并不总是能在线程中的子例程调用中幸存:
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
Run Code Online (Sandbox Code Playgroud)
使用全局范围更广的变量也可以,因此并不是所有变量都丢失了–似乎是动态变量:
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
Run Code Online (Sandbox Code Playgroud)
一旦将变量设置为foo(),就可以毫无问题地读取它bar()。但是,当bar()从promise内部调用时,for的值&*z不会在递归的第一层消失,而在第二层消失。
我感觉到一个错误,但也许我在递归/动态变量/线程之间做些奇怪的事情,使事情变得混乱。
在当前语义下,start将捕获在其内调用的上下文。如果动态变量查找在start执行该线程的堆栈(线程池中的线程池之一)上失败,则将退回到查看所捕获的动态范围当start块调度。
start在执行另一个start块的过程中创建一个块时,也会发生同样的事情。但是,两者之间没有关系,这意味着start也不会搜索“外部” 块捕获的上下文。尽管可以为这种情况辩护,但这样做似乎有潜在的问题。考虑以下示例:
sub tick($n = 1 --> Nil) {
start {
await Promise.in(1);
say $n;
tick($n + 1);
}
}
tick();
sleep;
Run Code Online (Sandbox Code Playgroud)
这是每秒产生刻度的一种(并非完全惯用的)方法。如果内部start为了保持动态变量查找的目的而保留了对外部状态的引用,则此程序将在内存中建立一个链,链的长度不断增加,这似乎是不受欢迎的行为。