在我根據我的Unix for Perl programmers: pipes and processes亞倫起重機工作結束;儘管在這些筆記中,他簡化了一些不處理從多個進程中讀取而沒有鎖定的內容(在這些筆記中臨時文件用於第二個流)。
的代碼只使用Test::More,沒有非核心Perl模塊
#!/usr/bin/perl
use warnings;
use strict;
use POSIX qw(dup2);
use Fcntl qw(:DEFAULT);
use IO::Handle;
use IO::Select;
use IO::Pipe;
use Test::More;
# [...]
# from http://aaroncrane.co.uk/talks/pipes_and_processes/
sub fork_child (&) {
my ($child_process_code) = @_;
my $pid = fork();
die "Failed to fork: $!\n" if !defined $pid;
return $pid if $pid != 0;
# Now we're in the new child process
$child_process_code->();
exit;
}
sub parallel_run (&) {
my $child_code = shift;
my $nchildren = 2;
my %children;
my (%pid_for_child, %fd_for_child);
my $sel = IO::Select->new();
foreach my $child_idx (1..$nchildren) {
my $pipe = IO::Pipe->new()
or die "Failed to create pipe: $!\n";
my $pid = fork_child {
$pipe->writer()
or die "$$: Child \$pipe->writer(): $!\n";
dup2(fileno($pipe), fileno(STDOUT))
or die "$$: Child $child_idx failed to reopen stdout to pipe: $!\n";
close $pipe
or die "$$: Child $child_idx failed to close pipe: $!\n";
# From Test-Simple-0.96/t/subtest/fork.t
#
# Force all T::B output into the pipe (redirected to STDOUT),
# for the parent builder as well as the current subtest builder.
{
no warnings 'redefine';
*Test::Builder::output = sub { *STDOUT };
*Test::Builder::failure_output = sub { *STDOUT };
*Test::Builder::todo_output = sub { *STDOUT };
}
$child_code->();
*STDOUT->flush();
close(STDOUT);
};
$pid_for_child{$pid} = $child_idx;
$pipe->reader()
or die "Failed to \$pipe->reader(): $!\n";
$fd_for_child{$pipe} = $child_idx;
$sel->add($pipe);
$children{$child_idx} = {
'pid' => $pid,
'stdout' => $pipe,
'output' => '',
};
}
while (my @ready = $sel->can_read()) {
foreach my $fh (@ready) {
my $buf = '';
my $nread = sysread($fh, $buf, 1024);
exists $fd_for_child{$fh}
or die "Cannot find child for fd: $fh\n";
if ($nread > 0) {
$children{$fd_for_child{$fh}}{'output'} .= $buf;
} else {
$sel->remove($fh);
}
}
}
while (%pid_for_child) {
my $pid = waitpid -1, 0;
warn "Child $pid_for_child{$pid} ($pid) failed with status: $?\n"
if $? != 0;
delete $pid_for_child{$pid};
}
return map { $children{$_}{'output'} } keys %children;
}
# [...]
@output = parallel_run {
my $data = $cache->compute($key, \&get_value_slow);
print $data;
};
is_deeply(
\@output,
[ ($value) x 2 ],
'valid data returned by both process'
);
一切都是白色盒子 - 這是我自己的代碼。我總是可以從測試中分離出來,但問題在於收集來自兒童的數據。 – 2010-10-29 19:30:42