并发,一次响应多个供应

Hol*_*lli 9 rakudo perl6 raku

请考虑以下代码。为什么输出的是“ BABABA”而不是“ AAABAA” /“ AABAAAB”?这两个供应源不应该并行运行,并且当其中任何一个事件发生时立即火起来吗?

my $i = 0; 
my $supply1 = supply { loop { await Promise.in(3); done if $i++> 5; emit("B"); } };
my $supply2 = supply { loop { await Promise.in(1); done if $i++> 5; emit("A"); } };

react 
{ 
    #whenever Supply.merge($supply1, $supply2) -> $x { $x.print }
    whenever $supply1 -> $x { $x.print };
    whenever $supply2 -> $x { $x.print };
}
Run Code Online (Sandbox Code Playgroud)

Jon*_*ton 7

当我们订阅一个supply块时,该块的主体supply立即运行以设置订阅。在此过程中,没有引入并发。如果我们想要的话,我们需要要求它。

最佳解决方案取决于示例与您正在做的事情的距离。如果非常接近-并且您希望emit每个时间间隔都进行赋值-那么解决方案是Supply.interval改用:

my $i = 0; 
my $supply1 = supply { whenever Supply.interval(3, 3) { done if $i++ > 5; emit("B"); } };
my $supply2 = supply { whenever Supply.interval(1, 1) { done if $i++> 5; emit("A"); } };

react { 
    whenever $supply1 -> $x { $x.print };
    whenever $supply2 -> $x { $x.print };
}
Run Code Online (Sandbox Code Playgroud)

只需设置一个订阅即可退出设置,从而获得所需的输出,但是您确实在上进行了数据竞争$i

更通用的模式是做任何使循环在设置步骤之外发生的事情。例如,我们可以使用a容器Promise来“ thunk”它:

my constant READY = Promise.kept;
my $i = 0;
my $supply1 = supply whenever READY {
    loop { await Promise.in(3); done if $i++> 5; emit("B"); }
}
my $supply2 = supply whenever READY {
    loop { await Promise.in(1); done if $i++> 5; emit("A"); }
}

react { 
    whenever $supply1 -> $x { $x.print };
    whenever $supply2 -> $x { $x.print };
}
Run Code Online (Sandbox Code Playgroud)

这有帮助,因为a的结果Promisesupply通过线程池调度程序传递到块,从而将whenever包含循环的内容强制执行到自己的预定任务中。

这不是特别漂亮,但是如果我们定义一个函数来做到这一点:

sub asynchronize(Supply $s) {
    supply whenever Promise.kept {
        whenever $s { .emit }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,原始程序只需要添加两个调用即可:

my $i = 0;
my $supply1 = supply { loop { await Promise.in(3); done if $i++> 5; emit("B") } }
my $supply2 = supply { loop { await Promise.in(1); done if $i++> 5; emit("A") } }

react { 
    whenever asynchronize $supply1 -> $x { $x.print }
    whenever asynchronize $supply2 -> $x { $x.print }
}
Run Code Online (Sandbox Code Playgroud)

为了使其按需工作。可以说,这样的东西应该作为内置提供。

根据Channel其他解决方案的建议,也可以使用,这取决于当前合适的问题。这个问题与实际问题有点过抽象,我无法说。该解决方案处于Supply范式之内,在这种意义上更为整洁。