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