每秒打印一次,并且在Perl 6中使用反应时也会在5秒钟内停留10秒钟?

che*_*nyf 12 perl6 raku

我想每秒打印当前时间,也想睡5秒钟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;
    }
}
Run Code Online (Sandbox Code Playgroud)

输出不是我想要的:

1542371045
Sleep Done
1542371055
Sleep Done
1542371065
Sleep Done
1542371075
Done.
...
Run Code Online (Sandbox Code Playgroud)

我想要的是这个:

1542371045
1542371046
1542371047
1542371048
1542371049 
Sleep Done
1542371059
1542371060
1542371061  
1542371062 
1542371063         
Sleep Done
Done.
Run Code Online (Sandbox Code Playgroud)

不太了解Promise,Supply...关于Perl 6,这可能吗?

Jon*_*ton 11

根据具体需要的其他内容,我可能会写这样的东西:

react {
    sub sequence() {
        whenever Supply.interval(1).head(5) {
            say DateTime.now.posix;
            LAST whenever Promise.in(10) {
                say "Sleep done";
                sequence();
            }
        }
    }
    sequence();
}   
Run Code Online (Sandbox Code Playgroud)

这给出了这样的输出:

1542395158
1542395159
1542395160
1542395161
1542395162
Sleep done
1542395172
1542395173
1542395174
1542395175
1542395176
Sleep done
1542395186
1542395187
1542395188
...
Run Code Online (Sandbox Code Playgroud)

这将绝对确保你在10秒暂停之间得到5个滴答声; 使用两个单独的间隔供应 - 就像在这里的许多解决方案中一样 - 不会给出任何严格的保证,并且可能偶尔会错过.(一个不是可爱的rotor,如果你不需要实际打印"完成睡眠"的事情,这是一个很好的选择).它也没有状态(变量)和条件,这是相当不错的.

虽然这看起来可能是递归的,但由于它whenever是一个异步循环结构,它实际上根本不会构建一个调用堆栈.

它也完全由异步构造构建,因此在Perl 6.d中,如果react在线程池上触发,则不会阻塞真正的OS线程.所以你可以有成千上万的活跃.相比之下,sleep将阻止一个真正的线程,这是sleep传统上预期会做的,但如果不处理异步结构,则不是很合适.


Bra*_*ert 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

这不是很清楚.
我们只是用它.rotor来跳过每隔3个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;
    }
}
Run Code Online (Sandbox Code Playgroud)

虽然我们在这里,为什么不在供应.rotor上使用.interval(1)

react {
    whenever Supply.interval(1).rotor(1 xx 4, 1 => 10) {
        say DateTime.now.posix;
    }

    whenever signal(SIGINT) {
        say "Done.";
        done;
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,我们不能只使用它,5 => 10因为它将它们批量化,我们希望它们可以单独运行.


请注意,这.grep也适用于Supplys,因此我们可以使用它来检查$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;
    }
}
Run Code Online (Sandbox Code Playgroud)


che*_*nyf 5

也许这可以工作:

loop {
    react {
        whenever Supply.interval(1) {
            say DateTime.now.posix;
        }

        whenever Promise.in(5) {
            done;
        }

        whenever signal(SIGINT) {
            say "Done.";
            done;
        }
    }
    sleep 10;
}
Run Code Online (Sandbox Code Playgroud)

输出为:

1542347961
1542347962
1542347963
1542347964
1542347965
1542347976 # <- 10s
1542347977
1542347978
1542347979
1542347980
1542347991 # <- 10s
Run Code Online (Sandbox Code Playgroud)