我有一个小程序,运行到收到SIGINT或收到来自stdin的两行(按Enter键两次)。反应块逻辑为:
react {
whenever signal(SIGINT) {
say "Got signal";
exit;
}
whenever $*IN.lines.Supply {
say "Got line";
exit if $++ == 1 ;
}
}
Run Code Online (Sandbox Code Playgroud)
程序将按预期在两行输入中退出。
但是,CTRL-C不会执行任何操作,除非它后跟一行(输入)。
如果我切换everyever块的顺序,则程序会被SIGINT中断,但无论何时都不会执行信号
react {
whenever $*IN.lines.Supply {
say "Got line";
exit if $++ == 1 ;
}
whenever signal(SIGINT) {
say "Got signal";
exit;
}
}
Run Code Online (Sandbox Code Playgroud)
使用信号接头之前是否还需要其他设置?在反应块中,每当块的顺序重要吗?
更新资料
因此,似乎lines()调用阻止了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
Run Code Online (Sandbox Code Playgroud)
为什么它的行为与我的原始代码如此不同?
如果数据源确实以异步方式运行,则顺序无关紧要,不幸的是,这里不是这种情况。Supplya上的强制转换Seq不会引入任何并发性,并且会立即尝试产生要在上发出的值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;
}
}
Run Code Online (Sandbox Code Playgroud)
将来的Perl 6版本中可能会对该领域进行一些修订。当前的行为意料之中;设计原则是避免遵循隐式引入并发的一般原则,即供应是管理固有存在的并发而不是引入并发的工具。但是,实际上,这里缺乏并发性可能使更多人受益。(此外,我们可能会考虑提供真正的非阻塞文件I / O,而不是从同步文件I / O +线程构建它。)