需要帮助理解 Perl 代码 - 多进程/fork
Need help understanding Perl code- Multi process / fork
我正在寻找一个示例,以将分叉进程的数量同时限制为 运行,并且我 运行 跨越了这个旧代码
#!/usr/bin/perl
#total forks, max childs, what to run
#function takes 2 scalars and a reference to code to run
sub mfork ($$&) {
my ($count, $max, $code) = @_;
# total number of processes to spawn
foreach my $c (1 .. $count) {
#what is happening here? why wait vs waitpid?
wait unless $c <= $max;
die "Fork failed: $!\n" unless defined (my $pid = fork);
# i don't undestand the arrow notation here and how it calls a function,
#also unless $pid is saying run function unless you're the parent
exit $code -> ($c) unless $pid;
}
#no idea what's happening here, why are we waiting twice? for the last process?
#why 1 until (-1 == wait)? what's 1 doing here
1 until -1 == wait;
}
#code to run
mfork 10, 3, sub {
print "$$: " . localtime() . ": Starting\n";
select undef, undef, undef, rand 2;
print "$$: " . localtime() . ": Exiting\n";
};
让我们看一下代码。代码是你的,你的大部分评论都被删除了。所有其他评论都是我的。
#!/usr/bin/perl
# total forks, max childs, what to run
# function takes 2 scalars and a reference to code to run
sub mfork ($$&) {
my ($count, $max, $code) = @_;
# total number of processes to spawn
foreach my $c (1 .. $count) {
# wait waits for any child to return,
# waitpid for a specific one
wait unless $c <= $max;
die "Fork failed: $!\n" unless defined (my $pid = fork);
# the arrow is used to call the coderef in $code
# and the argument is $c. It's confusing because it has
# the space. It's a deref arrow, but looks like OOp.
# You're right about the 'unless $pid' part.
# If there is $pid it's in the parent, so it does
# nothing. If it is the child, it will run the
# code and exit.
exit $code -> ($c) unless $pid;
}
# This is reached after the parent is done with the foreach.
# It will wait in the first line of the foreach while there are
# still $count tasks remaining. Once it has spawned all of those
# (some finish and exit and make room for new ones inside the
# loop) it gets here, where it waits for the remaining ones.
# wait will return -1 when there are no more children.
# The '1 until' is just short for having an until loop that
# doesn't have the block. The 1; is not a costly operation.
# When wait == -1 it passes the line, returning from the sub.
1 until -1 == wait;
}
# because of the prototype above there are no () needed here
mfork 10, 3, sub {
print "$$: " . localtime() . ": Starting\n";
select undef, undef, undef, rand 2;
print "$$: " . localtime() . ": Exiting\n";
};
让我们详细看一下东西。
- 有
wait
and waitpid
个。 wait
将 等待 直到 children returns 中的任何一个。这很有用,因为程序不关心释放了哪个 slot。一旦一个完成,就可以产生一个新的。 waitpid
采用特定 $pid
的参数。这在这里没有帮助。
$code->($c)
语法 运行 是一个代码参考。就像 %{ $foo }{bar}
将取消引用哈希引用一样,&{ $baz }()
将取消引用(和 运行,即 ()
)代码引用。更容易阅读的方式是 $foo->{bar}
。 $baz->()
也是如此。 arraow 取消引用它。参见 perlref and perlreftut。
虽然这很好用而且有用,但使用 Parallel::Forkmanager 可能更有意义,它以更少的代码行提供了它的强大功能,而且您无需担心它是如何实现的有效。
use strict;
use warnings;
use Parallel::ForkManager;
my $pm = Parallel::ForkManager->new(3); # max 3 at the same time
DATA_LOOP:
foreach my $data (1 .. 10) {
# Forks and returns the pid for the child:
my $pid = $pm->start and next DATA_LOOP;
... do some work with $data in the child process ...
print "$$: " . localtime() . ": Starting\n";
select undef, undef, undef, rand 2;
print "$$: " . localtime() . ": Exiting\n";
$pm->finish; # Terminates the child process
}
就是这样。阅读起来更清晰。 :)
我正在寻找一个示例,以将分叉进程的数量同时限制为 运行,并且我 运行 跨越了这个旧代码
#!/usr/bin/perl
#total forks, max childs, what to run
#function takes 2 scalars and a reference to code to run
sub mfork ($$&) {
my ($count, $max, $code) = @_;
# total number of processes to spawn
foreach my $c (1 .. $count) {
#what is happening here? why wait vs waitpid?
wait unless $c <= $max;
die "Fork failed: $!\n" unless defined (my $pid = fork);
# i don't undestand the arrow notation here and how it calls a function,
#also unless $pid is saying run function unless you're the parent
exit $code -> ($c) unless $pid;
}
#no idea what's happening here, why are we waiting twice? for the last process?
#why 1 until (-1 == wait)? what's 1 doing here
1 until -1 == wait;
}
#code to run
mfork 10, 3, sub {
print "$$: " . localtime() . ": Starting\n";
select undef, undef, undef, rand 2;
print "$$: " . localtime() . ": Exiting\n";
};
让我们看一下代码。代码是你的,你的大部分评论都被删除了。所有其他评论都是我的。
#!/usr/bin/perl
# total forks, max childs, what to run
# function takes 2 scalars and a reference to code to run
sub mfork ($$&) {
my ($count, $max, $code) = @_;
# total number of processes to spawn
foreach my $c (1 .. $count) {
# wait waits for any child to return,
# waitpid for a specific one
wait unless $c <= $max;
die "Fork failed: $!\n" unless defined (my $pid = fork);
# the arrow is used to call the coderef in $code
# and the argument is $c. It's confusing because it has
# the space. It's a deref arrow, but looks like OOp.
# You're right about the 'unless $pid' part.
# If there is $pid it's in the parent, so it does
# nothing. If it is the child, it will run the
# code and exit.
exit $code -> ($c) unless $pid;
}
# This is reached after the parent is done with the foreach.
# It will wait in the first line of the foreach while there are
# still $count tasks remaining. Once it has spawned all of those
# (some finish and exit and make room for new ones inside the
# loop) it gets here, where it waits for the remaining ones.
# wait will return -1 when there are no more children.
# The '1 until' is just short for having an until loop that
# doesn't have the block. The 1; is not a costly operation.
# When wait == -1 it passes the line, returning from the sub.
1 until -1 == wait;
}
# because of the prototype above there are no () needed here
mfork 10, 3, sub {
print "$$: " . localtime() . ": Starting\n";
select undef, undef, undef, rand 2;
print "$$: " . localtime() . ": Exiting\n";
};
让我们详细看一下东西。
- 有
wait
andwaitpid
个。wait
将 等待 直到 children returns 中的任何一个。这很有用,因为程序不关心释放了哪个 slot。一旦一个完成,就可以产生一个新的。waitpid
采用特定$pid
的参数。这在这里没有帮助。 $code->($c)
语法 运行 是一个代码参考。就像%{ $foo }{bar}
将取消引用哈希引用一样,&{ $baz }()
将取消引用(和 运行,即()
)代码引用。更容易阅读的方式是$foo->{bar}
。$baz->()
也是如此。 arraow 取消引用它。参见 perlref and perlreftut。
虽然这很好用而且有用,但使用 Parallel::Forkmanager 可能更有意义,它以更少的代码行提供了它的强大功能,而且您无需担心它是如何实现的有效。
use strict;
use warnings;
use Parallel::ForkManager;
my $pm = Parallel::ForkManager->new(3); # max 3 at the same time
DATA_LOOP:
foreach my $data (1 .. 10) {
# Forks and returns the pid for the child:
my $pid = $pm->start and next DATA_LOOP;
... do some work with $data in the child process ...
print "$$: " . localtime() . ": Starting\n";
select undef, undef, undef, rand 2;
print "$$: " . localtime() . ": Exiting\n";
$pm->finish; # Terminates the child process
}
就是这样。阅读起来更清晰。 :)