并发,一次对多个供应做出反应 [英] Concurrency, react-ing to more than one supply at a time

查看:55
本文介绍了并发,一次对多个供应做出反应的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑下面的代码.为什么这个输出是BABABA"而不是AABABAA"/AABAAAB"?当其中任何一个发生事件时,这两个电源不应该并行运行并立即触发吗?

Please consider the code below. Why is the output of this is "BABABA" and not "AAABAA" / "AABAAAB"? Shouldn't the two supplies run in parallel and the whenever fire immedeatly when there is an event in any of them?

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 };
}

推荐答案

当我们订阅一个 supply 块时,该 supply 块的主体会立即按顺序运行设置订阅.作为其中的一部分,没有引入并发性;如果我们想要那个,我们需要要求它.

When we subscribe to a supply block, the body of that supply block is run immediately in order to set up subscriptions. There's no concurrency introduced as part of this; if we want that, we need to ask for it.

最佳解决方案取决于示例与您正在做的事情的接近程度.如果它非常接近 - 并且您想在每个时间间隔 emit 值 - 那么解决方案是使用 Supply.interval 代替:

The best solution depends on how close the example is to what you're doing. If it's very close - and you want to emit values every time interval - then the solution is to use Supply.interval instead:

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 };
}

这只是简单地设置订阅并退出设置,从而提供您想要的输出,但是您在 $i 上确实存在数据竞争.

Which simply sets up a subscription and gets out of the setup, and so gives the output you want, however you do have a data race on the $i.

更一般的模式是只做任何事情,使循环发生在设置步骤之外.例如,我们可以使用一个保留的 Promise 来thunk"它:

The more general pattern is to just do anything that gets the loop happening out of the setup step. For example, we could use an a kept Promise to just "thunk" it:

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 };
}

这有帮助,因为 Promise 的结果将通过线程池调度器传递到 supply 块,从而强制执行 的内容每当 - 包含循环 - 进入它自己的计划任务.

Which helps because the result of a Promise will be delivered to the supply block via the thread pool scheduler, thus forcing the execution of the content of the whenever - containing the loop - into its own scheduled task.

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

This isn't especially pretty, but if we define a function to do it:

sub asynchronize(Supply $s) {
    supply whenever Promise.kept {
        whenever $s { .emit }
    }
}

那么原来的程序只需要对它增加两次调用:

Then the original program only needs the addition of two calls to it:

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 }
}

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

To make it work as desired. Arguably, something like this should be provided as a built-in.

也可以使用Channel,正如其他解决方案所建议的那样,并且取决于可能适合的手头问题;这个问题对我来说有点过于抽象了一个真正的问题.此解决方案保持在 Supply 范式内,在这个意义上更简洁.

It is possible to use a Channel as well, as the other solution proposes, and depending on the problem at hand that may be suitable; the question is a bit too abstracted from a real problem for me to say. This solution stays within the Supply paradigm, and is neater in that sense.

这篇关于并发,一次对多个供应做出反应的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆