bash perl:执行多个系统进程并等待它们完成

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9253883/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 01:32:56  来源:igfitidea点击:

perl: executing multiple systems processes and waiting for them to finish

perlbashloggingfork

提问by Blaskovicz

Currently in my Perl script I make a call like the following:

目前在我的 Perl 脚本中,我进行了如下调用:

system(" ./long_program1 & ./long_program2 & ./long_program3 & wait ");

I would like to be able to log when each of the long running commands executes while still executing them asyncronously. I know that the system call causes perl to make a fork, so is something like this possible? Could this be replaced by multiple perl fork() and exec() calls?

我希望能够记录每个长时间运行的命令何时执行,同时仍然异步执行它们。我知道系统调用会导致 perl 创建一个 fork,那么这样的事情可能吗?这可以用多个 perl fork() 和 exec() 调用代替吗?

Please help me find a better solution.

请帮我找到更好的解决方案。

回答by DVK

Yes, definitely. You can fork off a child process for each of the programs to be executed.

当然是。您可以为每个要执行的程序创建一个子进程。

You can either do system()or exec()after forking, depending on how much processing you want your Perl code to do after the system call finishes (since exec() is very similar in functionality to system(); exit $rc;)

您可以执行system()exec()在分叉之后执行,具体取决于您希望 Perl 代码在系统调用完成后执行多少处理(因为 exec() 在功能上与 非常相似system(); exit $rc;

foreach my $i (1, 2, 3) {
    my $pid = fork();
    if ($pid==0) { # child
        exec("./long_program$i");
        die "Exec $i failed: $!\n";
    } elsif (!defined $pid) {
        warn "Fork $i failed: $!\n";
    }
}

1 while wait() >= 0;

Please note that if you need to do a lot of forks, you are better off controlling them via Parallel::ForkManagerinstead of doing forking by hand.

请注意,如果您需要做很多分叉,最好通过控制它们Parallel::ForkManager而不是手动分叉。

回答by ikegami

Two alternatives:

两种选择:



use IPC::Open3 qw( open3 );

sub launch {
   open(local *CHILD_STDIN, '<', '/dev/null') or die $!;
   return open3('<&CHILD_STDIN', '>&STDOUT', '>&STDERR', @_);
}

my %children;
for my $cmd (@cmds) {
   print "Command $cmd started at ".localtime."\n";
   my $pid = launch($cmd);
   $children{$pid} = $cmd;
}

while (%children) {
   my $pid = wait();
   die $! if $pid < 1;
   my $cmd = delete($children{$pid});
   print "Command $cmd ended at ".localtime." with $? = $?."\n";
}

I use open3since it it's shorter than a even trivial fork+execand since it doesn't misattribute execerrors to the command you launch like a trivial fork+exec.

我使用open3它是因为它比一个甚至微不足道的fork+还要短,exec并且因为它不会exec像微不足道的fork+那样将错误错误地归因于您启动的命令exec



use threads;

my @threads;
for my $cmd (@cmds) {
   push @threads, async {
      print "Command $cmd started at ".localtime."\n";
      system($cmd);
      print "Command $cmd ended at ".localtime." with $? = $?."\n";
   };
}

$_->join() for @threads;