Perl 如何从子进程传递变量(fork by Parallel::ForkManager)?

Perl 如何从子进程传递变量(fork by Parallel::ForkManager)?,perl,multiprocessing,fork,child-process,Perl,Multiprocessing,Fork,Child Process,我的问题是: 在下面的代码中,我尝试将print$commandoutput[0]移位或传递到即将到来的子例程中。我尝试了移位来传递它。但是我失败了。您能帮我找到正确的方法吗 代码: 在这里,我试图将print$commandoutput[0]存储在子例程内部的变量中。我在这里选择了如何将变量从外部传递到子例程内部 sub gen_help_data { my $lines=shift; print $lines; } 我想你误解了叉子的作用。当您成功地进行fork时,您正在创建一个子

我的问题是:

在下面的代码中,我尝试将print$commandoutput[0]移位或传递到即将到来的子例程中。我尝试了移位来传递它。但是我失败了。您能帮我找到正确的方法吗

代码:

在这里,我试图将print$commandoutput[0]存储在子例程内部的变量中。我在这里选择了如何将变量从外部传递到子例程内部

sub gen_help_data
{
  my $lines=shift;
  print $lines;
}

我想你误解了叉子的作用。当您成功地进行fork时,您正在创建一个子流程,独立于您开始的流程,以继续进行工作。因为它是一个独立的进程,所以它有自己的内存、变量等,即使其中一些是从父进程开始的副本

因此,您在每个子流程中设置$commandoutput[0],但当该子流程终止时,其@commandoutput副本的内容也会随之终止


您可以连续运行每个命令,也可以使用线程,这会带来许多其他问题-您的代码甚至需要一些重大的重新设计才能与线程一起工作,或者您可以使用events POE、AnyEvent等,这将是另一个重大的重新设计。或者,您可以运行每个命令,并将其输出放入临时文件中,然后在完成所有子项后,读取每个文件并继续。这也会带来一些问题,但通常比其他问题要少。

我认为你误解了叉子的作用。当您成功地进行fork时,您正在创建一个子流程,独立于您开始的流程,以继续进行工作。因为它是一个独立的进程,所以它有自己的内存、变量等,即使其中一些是从父进程开始的副本

因此,您在每个子流程中设置$commandoutput[0],但当该子流程终止时,其@commandoutput副本的内容也会随之终止

您可以连续运行每个命令,也可以使用线程,这会带来许多其他问题-您的代码甚至需要一些重大的重新设计才能与线程一起工作,或者您可以使用events POE、AnyEvent等,这将是另一个重大的重新设计。或者,您可以运行每个命令,并将其输出放入临时文件中,然后在完成所有子项后,读取每个文件并继续。这也会带来问题,但通常比其他问题要少。

开始和结束之间的代码在单独的进程中运行,即使使用相同的名称,子级和父级也无法写入彼此的变量。分叉创建了一个独立的进程,拥有自己的内存和数据。†要在这些进程之间传递数据,我们需要使用进程间通信机制

该模块确实提供了一种方便、简单的方法将数据从子级传递回父级。 参见文档中的

您首先需要提供以完成对子级要返回的数据结构的引用。在您的情况下,您希望返回标量$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_数据中,作为进程id键的值。因此,在foreach完成后,您可以在%ret_数据中找到所有数据

在这里,我们将$ret_data{$pid}作为标量引用取消引用,因为您的代码返回标量引用

请注意,数据是通过写出文件来传递的,如果进行了大量操作,则传递速度可能会很慢

下面是一个完整的示例,其中每个子级通过将数组引用传递给finish返回一个数组引用,然后在回调中检索该数组引用。有关不同的示例,请参见

印刷品

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 †在现代系统上,由于性能原因,在分叉新流程时尽可能少地复制数据。因此,子级通过分叉继承的变量实际上不是副本,因此子级实际上读取父级分叉时存在的变量

但是,父级无法访问子级在内存中写入的任何数据,并且子级不知道父级在分叉后写入的内容。如果在分叉时将该数据写入从父级继承的变量,则会发生数据复制,以便子级的新数据是独立的

数据的管理方式当然有微妙和复杂之处,显然,即使子系统中的数据发生变化,也会维护许多指针。我猜这主要是为了简化数据管理,减少复制;数据管理的粒度似乎比可变级别的粒度细得多

但这些都是实现细节,通常情况下,子级和父级不能戳对方的数据。

开始和结束之间的代码在一个单独的进程中运行,并且子级和父级即使使用相同的名称也不能写入对方的变量。分叉创建了一个独立的过程 有自己的内存和数据。†要在这些进程之间传递数据,我们需要使用进程间通信机制

该模块确实提供了一种方便、简单的方法将数据从子级传递回父级。 参见文档中的

您首先需要提供以完成对子级要返回的数据结构的引用。在您的情况下,您希望返回标量$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_数据中,作为进程id键的值。因此,在foreach完成后,您可以在%ret_数据中找到所有数据

在这里,我们将$ret_data{$pid}作为标量引用取消引用,因为您的代码返回标量引用

请注意,数据是通过写出文件来传递的,如果进行了大量操作,则传递速度可能会很慢

下面是一个完整的示例,其中每个子级通过将数组引用传递给finish返回一个数组引用,然后在回调中检索该数组引用。有关不同的示例,请参见

印刷品

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 †在现代系统上,由于性能原因,在分叉新流程时尽可能少地复制数据。因此,子级通过分叉继承的变量实际上不是副本,因此子级实际上读取父级分叉时存在的变量

但是,父级无法访问子级在内存中写入的任何数据,并且子级不知道父级在分叉后写入的内容。如果在分叉时将该数据写入从父级继承的变量,则会发生数据复制,以便子级的新数据是独立的

数据的管理方式当然有微妙和复杂之处,显然,即使子系统中的数据发生变化,也会维护许多指针。我猜这主要是为了简化数据管理,减少复制;数据管理的粒度似乎比可变级别的粒度细得多


但这些都是实现细节,一般来说,孩子和家长不能互相戳对方的数据。

如果需要数据共享,我非常喜欢使用Thread::Queue@Sobrique执行工作线程样式。一个可以很好地从p::FM中的孩子返回数据的人,请参阅我的答案。如果需要数据共享,我非常喜欢使用Thread::Queue@Sobrique执行worker threads样式,可以很好地从P::FM中的子级返回数据,请参阅我的答案。@examplefile很棒-让我知道更多解释是否有用。@examplefile很棒-让我知道更多解释是否有用。
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