我有一个小程序,它一直运行到收到SIGINT或收到来自标准输入的两行(按回车键两次)。反应块逻辑是:
react {
whenever signal(SIGINT) {
say "Got signal";
exit;
}
whenever $*IN.lines.Supply {
say "Got line";
exit if $++ == 1 ;
}
}
程序将按预期在输入的两行退出。
然而,CTRL-C不会做任何事情,除非它后面跟着一行(输入)。
如果我切换任何块的顺序,程序会被SIGINT中断,但不会执行任何块的信号
react {
whenever $*IN.lines.Supply {
say "Got line";
exit if $++ == 1 ;
}
whenever signal(SIGINT) {
say "Got signal";
exit;
}
}
在使用信号子之前是否需要一些其他设置?无论何时块的顺序在反应块中是否重要?
更新
因此,行()调用似乎阻止了react块的执行(感谢@Håkon)。我有点明白了。
与读取套接字的类似代码结构相比,我感到困惑。数据的存在(或缺乏)对执行的信号处理程序没有影响,在这个例子中它可以很好地读取行:
my $listener=IO::Socket::Async.listen("0.0.0.0",4432);
react {
whenever $listener {
whenever $_.Supply.lines() {
say "Got line";
}
}
whenever signal(SIGINT) {
say "Got signal";
exit;
}
}
#testing with:
# curl http://localhost:4432
为什么它的行为与我的原始代码如此不同?
如果数据源真的以异步方式运行,顺序并不重要,不幸的是,这里不是这种情况。Seq
上的Supply
强制程序不会引入任何并发,并且会立即尝试在Supply
上生成一个值以发出,这反过来又会阻止从$*IN
读取。因此,第二个订阅没有机会设置;相同的潜在问题会导致观察到的其他问题。
解决方案是强制读取发生在“其他地方”。我们可以使用Supply. from-list(…)
来做到这一点,并告诉它我们真的想使用当前调度程序而不是其默认的CurrentThreadScheduler
。因此,这表现为需要:
react {
whenever Supply.from-list($*IN.lines, scheduler => $*SCHEDULER) {
say "Got line";
exit if $++ == 1 ;
}
whenever signal(SIGINT) {
say "Got signal";
exit;
}
}
在未来的Perl 6版本中,这一领域可能会有所修改。目前的行为是出于好意;设计原则是避免隐式引入并发,遵循一般原则,即供应是管理固有并发的工具,而不是引入并发。然而,实际上,这里缺乏并发可能会让更多的人绊倒,而不是有所帮助。(此外,我们可能会考虑提供真正的非阻塞文件I/O,而不是从同步文件I/O线程构建它。)
这是一个运行信号处理程序的变体(基于此答案),但不幸的是$*IN
的自动刷新似乎被关闭了:
my $lines = supply {
whenever start $*IN.lines.Supply {
whenever .lines { .emit }
}
}.Channel;
react {
whenever signal(SIGINT) {
say "Got signal";
exit;
}
whenever $lines {
say "Got line: '{$_}'";
exit if $++ == 1;
}
}
现在您必须按CTRL-D
打印行,然后它打印作为连接字符串输入的所有行,之后$*IN
关闭…在这种情况下,如何为$*IN
打开自动刷新?