Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Perl 如何等待子进程在父进程中设置变量? 使用Parallel::ForkManager; 我的$number\u running=0; my$pm=新的并行::ForkManager(30); $pm->run_on_start(sub{++$number_running;}); $pm->run_on_finish(sub{--$number_running;}); 因为(我的$i=0;$i0){}}永远等待着 $pm->开始和下一步; 打印$i; $pm->finish; }_Perl_Parallel Processing_Fork_Ipc_Child Process - Fatal编程技术网

Perl 如何等待子进程在父进程中设置变量? 使用Parallel::ForkManager; 我的$number\u running=0; my$pm=新的并行::ForkManager(30); $pm->run_on_start(sub{++$number_running;}); $pm->run_on_finish(sub{--$number_running;}); 因为(我的$i=0;$i0){}}永远等待着 $pm->开始和下一步; 打印$i; $pm->finish; }

Perl 如何等待子进程在父进程中设置变量? 使用Parallel::ForkManager; 我的$number\u running=0; my$pm=新的并行::ForkManager(30); $pm->run_on_start(sub{++$number_running;}); $pm->run_on_finish(sub{--$number_running;}); 因为(我的$i=0;$i0){}}永远等待着 $pm->开始和下一步; 打印$i; $pm->finish; },perl,parallel-processing,fork,ipc,child-process,Perl,Parallel Processing,Fork,Ipc,Child Process,上面的代码用于使用并行进程在for循环中执行代码。它计算正在运行的子进程的数量,并相应地设置$number\u running变量。一旦有5个子进程正在运行,我希望它等到0个子进程正在运行后再继续 for循环中的第一行就是为了实现这一点而设计的,但它永远都在那一行等待。这就像子进程对变量所做的更改对该行代码不可用一样。我做错了什么?注意:我知道wait_all_children,但我不想使用它。Short回调run_on_finish通常不会为每个孩子的退出触发,因此$number_runnin

上面的代码用于使用并行进程在for循环中执行代码。它计算正在运行的子进程的数量,并相应地设置
$number\u running
变量。一旦有5个子进程正在运行,我希望它等到0个子进程正在运行后再继续


for循环中的第一行就是为了实现这一点而设计的,但它永远都在那一行等待。这就像子进程对变量所做的更改对该行代码不可用一样。我做错了什么?注意:我知道
wait_all_children
,但我不想使用它。

Short回调
run_on_finish
通常不会为每个孩子的退出触发,因此
$number_running
不会减少,因此它无法控制循环。解决此问题的方法:

  • 使用
    eaw_finished_children
    在单个子项退出时进行通信,这样
    run_on_finish
    确实可以在每个子项退出时运行

  • 使用
    wait\u for\u available\u procs
    等待整个批次完成,然后再开始新批次

对于标题,子进程不能在父进程中设置任何内容(父进程也不能在子进程中设置任何内容)。他们必须以本模块中针对该姿势概述的方式进行沟通,以达成一致行动



回调
run\u on\u start
随每个新进程一起运行,计数器递增。但回调
run\u on\u finish
从未触发,因此计数器从未递减。因此,一旦到达
5
时,代码就位于
while
循环中。请注意,父级和子级是独立的过程,因此不知道彼此的变量,也无法更改它们


回调
run\u on\u finish
通常是在所有进程分叉后让
wait\u all\u子进程触发的。它的工作也完成了
当最大数量的进程运行且一个进程退出时。这在
start
中通过调用
wait\u one\u child
(在完成时调用
,见下文)完成

或者,这可以通过调用方法随意完成

这是一个非阻塞调用,用于获取子项并独立于对
start
wait\u all\u children
的调用执行回调。在很少调用
start
但希望快速执行回调的情况下使用此选项

这解决了如何在单个儿童退出时进行沟通的主要问题(如评论中所述),而不是通过
等待所有儿童

下面是一个如何使用它的示例,以便回调在子级退出时正确运行。大量代码仅用于诊断(打印)


直接的问题是如何等待整个批次完成后再开始新的批次。这可以通过以下方式直接完成:

等待,
$n
可用的进程插槽可用。如果未给出
$n
,则默认为1

如果
$MAX
用于
$n
,那么只有在整个批处理完成后,许多插槽才可用。
$n
使用什么也可以在运行时决定


模块操作的一些细节

当一个孩子退出时,
SIGCHLD
信号被发送到父代,它必须捕捉到该信号才能知道孩子已经离开了(首先是为了避免僵尸)。这是通过在代码中或在
SIGCHLD
处理程序中使用
wait
waitpid
完成的(但仅在一个位置)。看,还有

从中我们可以看出,这是在
wait\u one\u child
中完成的(通过
\u waitpid
sub)

wait\u all\u children

上面使用的方法
eaw\u finished\u children
是此方法的同义词

获取信号的方法
wait\u one\u child
用于
start
在最大进程数已满且有一个退出时获取子进程。这就是模块如何知道何时可以启动另一个进程并尊重其最大值。(它也被其他一些等待进程的例程使用。 )。此时,
$s->on\u finish($kid,…)

回调位于coderef
$code
中,从对象的
on_finish
键检索,该键本身在sub
run_on_finish
中设置。这就是回调函数的设置方式,一旦该子函数运行

用户可使用的方法有
等待所有子项
收获完成的子项


由于所有这些都未在发布的代码中使用,因此运行的
$number_
不会得到更新,因此
是一个无限循环。回想一下,父进程中运行的变量
$number\u
不能由子进程直接更改。

您不应该在这样的空闲循环中旋转。您的父进程将耗尽它所能获得的所有CPU时间,无休止地测试
$number\u running
的值。如何等待子进程将
$number\u running
减为零?@CJ7子进程不能影响父进程中使用的
$number\u running
——子进程和父进程不能相互写入变量。父级必须为自己递减此变量。请参阅我的答案中添加的说明。
每次子进程完成时都会执行run\u on\u finish
<代码>$number\u正在运行
是u
 use Parallel::ForkManager;    
 my $number_running = 0;
 my $pm = new Parallel::ForkManager(30); 
 $pm->run_on_start( sub { ++$number_running; } );
 $pm->run_on_finish( sub { --$number_running; } );
 for (my $i=0; $i<=100; $i++)
 {
     if ($number_running == 5) { while ($number_running > 0) {} }  # waits forever
     $pm->start and next;
     print $i;
     $pm->finish;
 }
use warnings;
use strict;
use feature 'say';
use Parallel::ForkManager;    
$| = 1;

my $total_to_process = 3;  # only a few for this test
my $number_running   = 0;    
my @ds;

my $pm = Parallel::ForkManager->new(30);

$pm->run_on_start( sub {
    ++$number_running;
    say "Started $_[0], total: $number_running";
});
$pm->run_on_finish( sub {
    --$number_running;
    my ($pid, $code, $iden, $sig, $dump, $rdata) = @_;
    push @ds, "gone-$pid";
    say "Cleared $pid, ", ($rdata->[0] // ''), ($code ? " exit $code" : '');
});

foreach my $i (1 .. $total_to_process)
{
    $pm->start and next;
    run_job($i);
    $pm->finish(10*$i, [ "kid #$i" ]);
}
say "Running: ", map { "$_ " } $pm->running_procs;  # pid's of children

# Reap right as each process exits, retrieve and print info
my $curr = $pm->running_procs;
while ($pm->running_procs) 
{
    $pm->reap_finished_children;    # may be fewer now
    if ($pm->running_procs < $curr) {
        $curr = $pm->running_procs;
        say "Remains: $number_running. Data: @ds";
    }
    sleep 1;  # or use Time::HiRes::sleep 0.1;
}

sub run_job {
    my ($num) = @_;
    my $sleep_time = ($num == 1) ? 1 : ($num == 2 ? 10 : 20);
    sleep $sleep_time;
    say "\tKid #$num slept for $sleep_time, exiting";
}
start: Started 4656, running: 1 start: Started 4657, running: 2 start: Started 4658, running: 3 Running: 4656 4658 4657 Kid #1 slept for 1, exiting Cleared 4656, kid #1 exit 10 Remains: 2. Data: gone-4656 Kid #2 slept for 10, exiting Cleared 4657, kid #2 exit 20 Remains: 1. Data: gone-4656 gone-4657 Kid #3 slept for 20, exiting Cleared 4658, kid #3 exit 30 Remains: 0. Data: gone-4656 gone-4657 gone-4658
sub wait_one_child { my ($s,$par)=@_;  
  my $kid;
  while (1) {
    $kid = $s->_waitpid(-1,$par||=0);
    last if $kid == 0 || $kid == -1; # AS 5.6/Win32 returns negative PIDs
    redo if !exists $s->{processes}->{$kid};
    my $id = delete $s->{processes}->{$kid};
    $s->on_finish( $kid, $? >> 8 , $id, $? & 0x7f, $? & 0x80 ? 1 : 0);
    last;
  }
  $kid;
};  
sub wait_all_children { my ($s)=@_;
  while (keys %{ $s->{processes} }) {
    $s->on_wait;
    $s->wait_one_child(defined $s->{on_wait_period} ? &WNOHANG : undef);
  };
}
sub on_finish {
  my ($s,$pid,@par)=@_;
  my $code=$s->{on_finish}->{$pid} || $s->{on_finish}->{0} or return 0;
  $code->($pid,@par);
};