在我根据我的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