perl - 如何并行运行 perl 脚本并捕获文件中的输出?

标签 perl redirect parallel-processing background stdout

我需要并行运行 Perl 测试,并为每个测试文件在单独的文件中捕获 STDOUT 和 STDERR。即使在一个文件中捕获,我也没有成功。我一直都这样,但没有运气。这就是我开始的地方(我不会给你带来所有的变化)。任何帮助是极大的赞赏。谢谢!

foreach my $file ( @files) {
    next unless $file =~ /\.t$/;
    print "\$file = $file\n";

    $file =~ /^(\w+)\.\w+/;
    
    my $file_pfx = $1;
    my $this_test_file_name = $file_pfx . '.txt';
    
    system("perl $test_dir\\$file > results\\$test_file_name.txt &") && die "cmd failed: $!\n";

}

最佳答案

这是一个使用 Parallel::ForkManager 的简单示例产生单独的进程。

在每个进程中,STDOUTSTDERR 流都被重定向,对于演示,有两种方式:STDOUT 到变量,然后可以根据需要传递(此处转储到文件中),并将 STDERR 直接传递到文件。或者使用库,并在单独的代码片段中提供示例。

数字1..6代表每个 child 将选择处理的数据批处理。仅立即启动三个进程,然后当一个进程完成时,另一个进程将在其位置启动。(在这里,它们几乎立即退出,“作业”微不足道。)

use warnings;
use strict;
use feature 'say';

use Carp qw(carp)        
use Path::Tiny qw(path); 
use Parallel::ForkManager; 

my $pm = Parallel::ForkManager->new(3); 

foreach my $data (1..6) { 
    $pm->start and next;     # start a child process
    proc_in_child($data);    # code that runs in the child process
    $pm->finish;             # exit it
}
$pm->wait_all_children;      # reap all child processes

say "\nParent $$ done\n";
    
sub proc_in_child {
    my ($data) = @_; 
    say "Process $$ with data $data";  # still shows on terminal

    # Will dump all that was printed to streams to these files
    my (outfile, $errfile) = 
        map { "proc_data-${data}_" . $_ . ".$$.out" } qw(stdout stderr);

    # Redirect streams
    # One way to do it, redirect to a variable (for STDOUT)...  
    open my $fh_stdout, ">", \my $so or carp "Can't open handle to variable: $!";
    my $fh_STDOUT = select $fh_stdout;
    # ...another way to do it, directly to a file (for any stream)
    # (first 'dup' it so it can be restored if needed)
    open my $SAVEERR, ">&STDERR"  or carp "Can't dup STDERR: $!";
    open *STDERR, ">", $errfile or carp "Can't redirect STDERR to $errfile: $!";

    # Prints wind up in a variable (for STDOUT) and a file (for STDERR)
    say  "STDOUT: Child process with pid $$, processing data #$data"; 
    warn "STDERR: Child process with pid $$, processing data #$data"; 

    close $fh_stdout;
    # If needed to restore (not in this example which exits right away)
    select $fh_STDOUT;
    open STDERR, '>&', $SAVEERR  or carp "Can't reopen STDERR: $!";

    # Dump all collected STDOUT to a file (or pass it around, it's a variable)
    path( $outfile )->spew($so);

    return 1
}

虽然STDOUT被重定向到变量,但STDERR不能以这种方式重定向,这里它直接转到文件。请参阅open 。不过,也有一些方法可以将其捕获到变量中。

然后您可以使用模块从子进程返回到父进程的功能,然后父进程可以处理这些变量。例如,参见this postthis postthis post 。 (还有更多,这些只是我所知道的。)或者实际上只是将它们转储到文件中,就像这里所做的那样。

另一种方法是使用可以运行代码和重定向输出的模块,例如 Capture::Tiny

use Capture::Tiny qw(capture);

sub proc_in_child {
    my ($data) = @_; 
    say "Process $$ with data $data";  # on terminal

    # Run code and capture all output
    my ($stdout, $stderr, @results) = capture {
          say  "STDOUT: Child process $$, processing data #$data";
          warn "STDERR: Child process $$, processing data #$data"; 

          # return results perhaps...
          1 .. 4;
    }

    # Do as needed with variables with collected STDOUT and STDERR
    # Return to parent, or dump to file:
    my ($outfile, $errfile) = 
        map { "proc_data-${data}_" . $_ . ".$$.out" } qw(stdout stderr);

    path($outfile) -> spew( $stdout );
    path($errfile) -> spew( $stderr );

    return 1
}    

这会保持相同数量的进程运行。或者,可以将其设置为等待整批完成,然后开始另一批。一些操作细节参见this post

关于perl - 如何并行运行 perl 脚本并捕获文件中的输出?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69286787/

相关文章:

perl - 如何提取美国国防部契约(Contract)信息以用于统计分析?

c# - 并行线程中的多个 dbcontext,EntityException "Rerun your statement when there are fewer active users"

Perl Net::SFTP::Foreign 断开连接不关闭连接

perl - 我如何在 perl 的 -e 的参数中使用文字单引号?

regex - 使用 Perl 捕获输出,直到找到特定模式

c# - 自定义错误页面中的 AspxErrorPath

python - 在 flask 中重定向时发出 POST 请求

redirect - 将 1and1 域指向 S3 存储桶

r - 插入符序列函数 - 无法找到变量 "optimismBoot"

使用 PPL 不锁定临界区的 C++ 并行循环