我需要并行运行 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 的简单示例产生单独的进程。
在每个进程中,STDOUT
和 STDERR
流都被重定向,对于演示,有两种方式: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 post和 this post和 this 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/