我的查询:
在下面的代码中,我试图将print $ commandoutput [0]移动或传递到即将到来的子程序。我尝试移动传递它。但是我失败了。可以请你帮我吧要遵循的方式?
代码:
my $max_forks = 4;
#createThreads();
my %commandData;
my @arr = (
'bhappy', 'bload -m all -l -res CPUSTEAL',
'bqueues', 'bjobs -u all -l -hfreq 101'
);
#print @arr;
my $fork = new Parallel::ForkManager($max_forks);
$fork->run_on_start(
sub {
my $pid = shift;
}
);
$fork->run_on_finish(
sub {
my ( $pid, $exit, $ident, $signal, $core ) = @_;
if ($core) {
print "PID $pid core dumped.\n";
}
else { }
}
);
my @Commandoutput;
my $commandposition = 0;
for my $command (@arr) {
$fork->start and next;
my @var = split( " ", $command );
$commandoutput[$commandposition] = `$command`;
$commandposition++;
$line = $commandoutput[0];
# print $line;
$fork->finish;
}
$fork->wait_all_children;
#print Dumper(\%commandData);
print $commandoutput[0];
在这里,我试图将print $ commandoutput [0]存储在子例程内的变量中。我在这里指出如何将变量从外部传递到子例程内部。
sub gen_help_data
{
my $lines=shift;
print $lines;
}
答案 0 :(得分:2)
我认为你误解了叉子的作用。当您成功分叉时,您将创建一个独立于您开始的流程的子流程,以继续工作。因为它是一个单独的进程,所以它有自己的内存,变量等,即使其中一些最初是从父进程复制的。
所以你在每个子流程中设置$commandoutput[0]
,但是当子流程消失时,@commandoutput
副本的内容也会消失。
您可以串行运行每个命令,也可以使用线程(其中包含许多其他问题 - 您的代码需要进行一些重要的重新设计才能使用线程),或者您可以使用事件(POE,AnyEvent,等,这将是另一个重要的重新设计)。或者你可以运行每个命令,并将其输出放入临时文件中,然后,一旦完成所有子项,读取每个文件并继续。这也带来了问题,但问题通常比其他问题少。
答案 1 :(得分:1)
start
和finish
之间的代码在单独的进程中运行,父和子无法访问彼此的数据(即使他们的变量恰好具有相同的名称,它们是不同的)。这是关于分叉的第一件事,它用自己的数据创建一个单独的过程。
但是这个模块确实提供了一种机制,您可以通过该机制从子节点传回数据。 请参阅文档中的Retrieving data structures from child processes。
首先需要向finish
提供对孩子想要返回的数据结构的引用。在您的情况下,您想要返回标量$commandoutput[0]
,所以
$fork->finish(0, \$commandoutput[0]);
然后在回调中找到此引用作为最后的第六个参数。你的代码遗漏了一个。所以在回调中你需要
my %ret_data; # to store data from different child processes
$pm->run_on_finish(
sub {
my ($pid, $exit, $ident, $signal, $core, $dataref) = @_;
$ret_data{$pid} = $dataref;
}
);
此处$dataref
为\$commandoutput[0]
,其存储在%ret_data
中,作为进程ID的键值。因此,在foreach
完成后,您可以在%ret_data
foreach my $pid (keys %ret_data) {
say "Data from $pid => ${$ret_data{$pid}}";
}
这里我们将$ret_data{$pid}
取消引用作为标量引用,因为您的代码会返回该值。
请注意,数据是通过写出文件来传递的,如果正在进行,可能会很慢。
这是一个完整的示例,其中每个子进程返回一个数组引用,方法是将其传递给finish
,然后在回调中检索它。有关其他示例,请参阅this post。
use warnings;
use strict;
use feature 'say';
use Parallel::ForkManager;
my $pm = Parallel::ForkManager->new(4);
my %ret_data;
$pm->run_on_finish( sub {
my ($pid, $exit, $ident, $signal, $core, $dataref) = @_;
$ret_data{$pid} = $dataref;
});
foreach my $i (1..8)
{
$pm->start and next;
my $ref = run_job($i);
$pm->finish(0, $ref);
}
$pm->wait_all_children;
foreach my $pid (keys %ret_data) {
say "$pid returned: @{$ret_data{$pid}}";
}
sub run_job {
my ($i) = @_;
return [ 1..$i ]; # make up return data: arrayref with list 1..$i
}
打印
15037 returned: 1 2 3 4 5 6 7 15031 returned: 1 2 15033 returned: 1 2 3 4 15036 returned: 1 2 3 4 5 6 15035 returned: 1 2 3 4 5 15038 returned: 1 2 3 4 5 6 7 8 15032 returned: 1 2 3 15030 returned: 1