进程间通信

运行程序

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

  1. run 'git', 'status';

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

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

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

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

Proc 对象

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

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

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

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

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

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

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

  1. my $crontab = run 'crontab', '-l';
  2. if $crontab.exitcode == 0 {
  3. say 'crontab -l ran ok';
  4. }
  5. else {
  6. say 'something went wrong';
  7. }

Proc::Async 对象

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

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

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

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

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

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