进程间通信

运行程序

许多程序需要能够运行其他程序,我们需要将信息传递给它们并接收它们的输出和退出状态。在 Raku 中运行程序非常简单:

run 'git', 'status';

这一行运行名为 “git” 的程序,并将 “git” 和 “status” 传递给它的命令行。它将使用 %*ENV<PATH> 设置找到该 git 程序。

如果您想通过向 shell 发送命令行来运行程序,那么也有一个工具。所有 shell 元字符都由 shell 解释,包括管道,重定向,环境变量替换等。

shell 'ls -lR | gzip -9 > ls-lR.gz';

使用 shell 用户输入时应小心。

Proc对象

runshell 都返回一个PROC对象,它可以使用具有更详细的进程进行通信。请注意,除非您关闭所有输出管道,否则程序通常不会终止。

my $git = run 'git', 'log', '--oneline', :out;
for $git.out.lines -> $line {
    my ($sha, $subject) = $line.split: ' ', 2;
    say "$subject [$sha]";
}
$git.out.close();

如果程序失败(以非零退出码退出),它将在返回的Proc对象沉没时抛出异常。您可以将其保存为变量,甚至是匿名变量,以防止下沉:

$ = run '/bin/false'; # does not sink the Proc and so does not throw 

您可以通过传递 :out:err 标志来告诉 Proc 对象将输出捕获为文件句柄。您也可以通过 :in 标记传递输入。

my $echo = run 'echo', 'Hello, world', :out;
my $cat  = run 'cat', '-n', :in($echo.out), :out;
say $cat.out.get;
$cat.out.close();

您还可以使用 Proc 捕获PID,将信号发送到应用程序,并检查 exitcode。

my $crontab = run 'crontab', '-l';
if $crontab.exitcode == 0 {
    say 'crontab -l ran ok';
}
else {
    say 'something went wrong';
}

Proc::Async对象

当您需要更多地控制与另一个进程的通信时,您将需要使用Proc::Async。该类提供对与程序进行异步通信的支持,以及向该程序发送信号的能力。

# Get ready to run the program 
my $log = Proc::Async.new('tail', '-f',  '/var/log/system.log');
$log.stdout.tap(-> $buf { print $buf });
$log.stderr.tap(-> $buf { $*ERR.print($buf) });
 
# Start the program 
my $done = $log.start;
sleep 10;
 
# Tell the program to stop 
$log.kill('QUIT');
 
# Wait for the program to finish 
await $done;

上面的小程序使用“tail”程序每 10 秒打印出名 system.log 的日志内容,然后通过 QUIT 信号告诉程序停止。

虽然 Proc 使用 IO::Handle 提供对输出的访问,但 Proc::Async 使用异步 supplies 提供访问(请参阅Supply)。

如果要在等待原始程序完成时运行程序并执行某些工作,则 start 例程将返回Promise,该程序在程序退出时保留(kept)。

使用 write 方法将数据传递到程序中。