我想每秒打印一次当前时间,并且还想睡10秒(非常5秒):
react {
whenever Supply.interval(1) {
say DateTime.now.posix;
}
whenever Supply.interval(5) {
sleep 10;
say 'Sleep Done';
}
whenever signal(SIGINT) {
say "Done.";
done;
}
}
输出不是我想要的:
1542371045
Sleep Done
1542371055
Sleep Done
1542371065
Sleep Done
1542371075
Done.
...
我想要的是什么
1542371045
1542371046
1542371047
1542371048
1542371049
Sleep Done
1542371059
1542371060
1542371061
1542371062
1542371063
Sleep Done
Done.
对Perl 6的Promise
,Supply
...了解不多吗?
答案 0 :(得分:11)
根据确切需要什么,我可能会这样写:
react {
sub sequence() {
whenever Supply.interval(1).head(5) {
say DateTime.now.posix;
LAST whenever Promise.in(10) {
say "Sleep done";
sequence();
}
}
}
sequence();
}
哪个给出这样的输出:
1542395158
1542395159
1542395160
1542395161
1542395162
Sleep done
1542395172
1542395173
1542395174
1542395175
1542395176
Sleep done
1542395186
1542395187
1542395188
...
这将确保您在10秒钟的暂停之间获得5个滴答声;像在这里的许多解决方案中那样,使用两个单独的间隔电源来执行此操作不会对此提供任何严格的保证,并且可能会时不时地打勾。 (不是一个可爱的rotor
,如果您不需要实际打印“完成睡眠”的东西,这是一个不错的选择)。它也没有状态(变量)和条件,这很好。
尽管看起来 可能是递归的,但由于whenever
是异步循环构造,因此实际上根本不会建立调用堆栈。
它也完全由异步结构构建而成,因此在Perl 6.d中,如果在线程池上触发了react
,则不会阻塞实际的OS线程。因此,您可能有成千上万的此类活动。相比之下,sleep
会阻塞一个真实的线程,这是sleep
传统上应该做的,但是如果不处理异步构造,则不是一个很好的选择。
答案 1 :(得分:8)
您犯的一个错误是,您假设耗材将丢失值,或者您假设react
被阻止时它们将停止生成值。
他们不会的。
他们不断创造价值。
您还应该尝试使whenever
中的代码运行时间尽可能短。
(假装它是CPU中断处理程序。)
该规则可能会有一些例外,特别是对于supply
块。
使用您提供的结构,这是实现所需功能的一种方法:
react {
# Are we ignoring the interval(1) values?
my Bool:D $ignore = False;
# The sleeping status of interval(5).
my Promise:D $sleep .= kept;
whenever Supply.interval(1) {
# Skip if it is supposed to be blocked.
next if $ignore;
say DateTime.now.posix;
}
# First one runs immediately, so skip it.
whenever Supply.interval(5).skip {
# Don't run while the “sleep” is pending.
next unless $sleep.status; # Planned
if $ignore {
$ignore = False;
say 'Sleep Done';
} else {
$ignore = True;
# Must be less than the multiple of 5 we want
# otherwise there may be a race condition.
$sleep = Promise.in(9);
}
}
whenever signal(SIGINT) {
say "Done.";
done;
}
}
不是很清楚。
那么,我们仅使用.rotor
跳过每5个间隔的第三个间隔又如何呢?
react {
my Bool:D $ignore = True;
# Note that first one runs immediately. (no .skip)
# We also want it to always be a few milliseconds before
# the other Supply, so we put it first.
# (Should have done that with the previous example as well.)
whenever Supply.interval(5).rotor(1, 1 => 1) {
$ignore = !$ignore;
}
whenever Supply.interval(1) {
next if $ignore;
say DateTime.now.posix;
}
whenever signal(SIGINT) {
say "Done.";
done;
}
}
我们正在努力,为什么不只在.rotor
供应上使用.interval(1)
?
react {
whenever Supply.interval(1).rotor(1 xx 4, 1 => 10) {
say DateTime.now.posix;
}
whenever signal(SIGINT) {
say "Done.";
done;
}
}
请注意,我们不能仅使用5 => 10
,因为那样会批量处理它们,我们希望它们可以单独运行。
请注意,.grep
也适用于耗材,因此我们可以使用它来检查$ignored
的值。
react {
my Bool:D $ignore = True;
whenever Supply.interval(5).rotor(1, 1 => 1) {
$ignore = !$ignore;
}
whenever Supply.interval(1).grep({ !$ignore }) {
say DateTime.now.posix;
}
whenever signal(SIGINT) {
say "Done.";
done;
}
}
答案 2 :(得分:4)
这可能有效吗
loop {
react {
whenever Supply.interval(1) {
say DateTime.now.posix;
}
whenever Promise.in(5) {
done;
}
whenever signal(SIGINT) {
say "Done.";
done;
}
}
sleep 10;
}
输出为:
1542347961
1542347962
1542347963
1542347964
1542347965
1542347976 # <- 10s
1542347977
1542347978
1542347979
1542347980
1542347991 # <- 10s
答案 3 :(得分:3)
问题是这两个耗材有效地在不同的线程中运行,因此不要互相影响。您的睡眠只会使它所处的线程进入睡眠状态(然后5秒钟的间隔实际上会导致另一个睡眠)。
要获得您想要的结果,我使用了1秒间隔和几个标志。
react {
whenever Supply.interval(1) {
state $slept = False;
state $count = 0;
if $count >= 0 {
if $slept {
say "Sleep Done";
$slept = False
}
say DateTime.now.posix;
}
$count++;
if ( $count == 5 ) {
$count = -9;
$slept = True
}
}
whenever signal(SIGINT) {
say "Done.";
done;
}
}
请注意,我们必须使用state
变量,因为“ everyth”块每秒都在其自己的线程中有效执行。状态变量使我们能够跟踪当前情况。
如果它以较小的间隔运行,我可能会考虑使用atomic int而不是普通的int(以防代码仍在运行时执行),但是该块执行的时间不应超过一秒钟,所以我不要以为这是个问题。
答案 4 :(得分:2)
由于任何时候都只会执行一个 whenever
,因此其中的sleep
将停止对事件做出反应的所有处理。实现所需目标的最简单方法是,将sleep
的代码包装到whenever
块中,作为异步工作来完成start
。
react {
whenever Supply.interval(1) {
say DateTime.now.posix;
}
whenever Supply.interval(5) {
start {
sleep 10;
say 'Sleep Done';
}
}
whenever signal(SIGINT) {
say "Done.";
done;
}
}
据我所见,这给出了所需的输出。