无序
Raku没有有序的消息队列。它有一个无序的需要完成的任务列表。
# schedule them to run at the same second
# just to make it more likely that they will be out of order
my $wait = now + 1;
my @run;
for 1..20 -> $n {
push @run, Promise.at($wait).then: {say $n}
}
await @run;
它可以按任何顺序打印数字。
1
2
3
4
5
6
7
8
11
12
13
14
15
16
17
18
9
10
19
20
Raku实际上是多线程的。如果你给它足够的工作,它会使用所有的CPU核心。
这意味着永远不可能有一种方法来说“在当前队列中的所有任务结束后再运行此任务”。
即使我只使用了start
,有时也会以错误的顺序运行任务。
my @run;
for 1..20 -> $n {
push @run, start {say $n}
};
await @run;
你可以多次运行这个程序,直到它开始打印出错乱的内容,但迟早会发生这种情况。
即使你使用低级别的 $*SCHEDULER.cue
,也不能保证它会在其他所有任务结束后再运行。
my @nums;
for 1..100 -> $n {
$*SCHEDULER.cue: {push @nums, $n; say $n}
}
say @nums;
它不仅可能出现故障,@nums
数组可能也没有所有的值,因为每个线程可能会覆盖另一个线程正在进行的操作。
在幕后,调度某些东西最终运行的 Promise 方法以某种方式调用 $*SCHEDULER.cue
。
将其它事物调度出去
您可以告诉 Raku 在其他事情之后运行您的代码。
my $p = Promise.in(1);
my $p2 = $p.then: {say 'first'}
my $p3 = $p.then: {say 'second'}
react {
whenever start say('first') {
whenever start say('second') {
}
}
}
但你需要有对那个东西的引用。
缓慢
如果Raku有一种方式可以在当前计划事件之后运行事物,那么它必须跟踪正在运行的内容,并确保你的代码在它们完成之后才能运行。
my $a = start {
# pointless busy-work that takes two seconds
my $wait = now + 2;
my $n = 0;
while now ≤ $wait {
$n++
}
say $n; # make sure the loop doesn't get optimized away
say 'first';
}
my $b = start say 'second';
await $a, $b;
second
1427387
first
如果确保
$b
在
$a
之后运行,那么
$b
将有两秒钟的空闲时间。相反,它会在另一个线程上运行,因为处理
$a
的线程目前正忙。这是一件好事,因为如果
$b
也很慢,我们就会安排两个缓慢的任务按顺序而不是并行运行。
Javascript
我认为它目前在Javascript中可行的唯一原因是它似乎没有利用多个CPU核心,或者它具有类似于GIL的东西。我编写了Raku代码,使我的4核CPU利用率达到500%(Intel超线程CPU,其中一个核心似乎是2个核心)。我不确定单个Javascript程序是否能做到同样的效果。