【问题标题】:2D arrays and Parallel::ForkManager, array is empty after forking and then assigning values?2D数组和Parallel::ForkManager,fork再赋值后数组为空?
【发布时间】:2013-06-07 08:23:42
【问题描述】:

我正在使用 forkmanager 同时而不是按顺序运行任务。我已将我的实际代码转换为以下代表我的代码逻辑的示例代码。

#!/usr/bin/perl -w 
use strict;
use Data::Dumper;
use Parallel::ForkManager;

my @array2d = () ;



my $dim1Items = 4;
my $dim2Items = 3;

my $dim1Manager = Parallel::ForkManager->new($dim1Items);
for (my $i = 0; $i <= $dim1Items ; $i++) {
        $dim1Manager->start and next;


        my $dim2Manager = Parallel::ForkManager->new($dim2Items);
        for (my $j = 0; $j <= $dim2Items; $j++) {
                $dim2Manager->start and next;

                $array2d[$i][$j] = "$i\t$j" ;

                $dim2Manager->finish;
        }
        $dim2Manager->wait_all_children;


        $dim1Manager->finish;
}
$dim1Manager->wait_all_children;

print Dumper(@array2D) ; 

然后我运行 Dumper(@2dArray) 来查看内容,但我得到的是空字符串,这意味着数组是空的。我在没有分叉的情况下尝试了我的值赋值语法并且它有效 - 所以我在分叉时一定做错了什么。

【问题讨论】:

  • 顺便说一句,您不应该将数组或哈希传递给Dumper。改为传递对它们的引用:Dumper(\@array2D)
  • 只是因为它更漂亮
  • 在我看来也像你的 for 循环中的一个错误;如果你从 0 到 $dim1Items 循环,那就是 $dim1Items+1 个总条目。

标签: arrays perl


【解决方案1】:

分叉是创建一个新进程,它是当前进程的副本。在一个进程中更改变量不会更改其他进程中类似命名的变量。

P::FM 确实提供了一种将数据传回父进程的机制。它是“从子进程中检索数据结构”标题下的 documented

use Data::Dumper          qw( Dumper );
use Parallel::ForkManager qw( );

use constant MAX_WORKERS => 10;
use constant { DIM1_ITEMS => 4, DIM2_ITEMS => 3 };

my @aoa;

my $pm = Parallel::ForkManager->new(MAX_WORKERS);
$pm->run_on_finish(sub {
   my ($pid, $exit_code, $ident, $exit_signal, $core_dump, $result_ref) = @_;
   my ($i, $j) = @$ident;

   warn("Child $i,$j killed by signal $exit_signal"), return if $exit_signal;
   warn("Child $i,$j exited with error $exit_code"),  return if $exit_code;
   warn("Child $i,$j encountered an unknown error"),  return if !$result_ref;

   $aoa[$i][$j] = $$result_ref;
});

for my $i (0..DIM1_ITEMS-1) {
   for my $j (0..DIM2_ITEMS-1) {
      $pm->start([ $i, $j ]) and next;

      my $result = "$i\t$j";

      $pm->finish(0, \$result);
   }
}

$pm->wait_all_children();

print(Dumper(\@aoa));

(像您那样拥有两个级别的 P::FM 是没有意义的。您应该拥有一个 F::PM,其最大子代数取决于您拥有的核心数量和一些实验。)

【讨论】:

  • 我有两个级别的 FM,因为我希望所有 12 (4 * 3) 个进程大致同时发生。在我的实际代码中,我正在运行一个需要很长时间才能运行的子程序,并在数组中返回一个我想要的字符串。
  • 就像我说的,这没有任何意义。一次做太多事情会使整个事情花费更长
【解决方案2】:

正如 ikegami 所说,子进程在其自己的内存空间中运行,并且它对变量所做的更改不会传播回父进程,除非您进行某种形式的进程间通信。 Forks::Super 模块使这种事情变得非常容易。

use Forks::Super;

my @array2d;
for my $i (0 .. 3) {
  for my $j (0 .. 2) {
    fork {
      share => [ \$array2d[$i][$j] ],
      sub => sub {
        sleep 1 + rand 4;
        $array2d[$i][$j] = "$i\t$j";
      },
    };
  }
}
waitall;
print Dumper(\@array2d);

【讨论】:

  • 也许将 MAX_PROC 添加到示例中(尽管在我看来,这个问题只是偶然限制了)
  • 有一个合理的默认MAX_PROC,取决于核心数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-12
  • 2019-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-29
相关资源
最近更新 更多