提问者:小点点

无论何时信号()在反应块顺序依赖?


我有一个小程序,它一直运行到收到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

为什么它的行为与我的原始代码如此不同?


共2个答案

匿名用户

如果数据源真的以异步方式运行,顺序并不重要,不幸的是,这里不是这种情况。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打开自动刷新?