我注意到Parallel::Loops模块用作$_其 subref 的参数。这个问题与Parallel::Loops本身无关,而是与 coderef 调用约定有关。
这是他们的示例,请注意$_传递给子:
$pl->foreach( \@parameters, sub {
# This sub "magically" executed in parallel forked child
# processes
# Lets just create a simple example, but this could be a
# massive calculation that will be parallelized, so that
# $maxProcs different processes are calculating sqrt
# simultaneously for different values of $_ on different CPUs
# (Do see 'Performance' / 'Properties of the loop body' below)
$returnValues{$_} = sqrt($_);
});
Run Code Online (Sandbox Code Playgroud)
...但我总是使用$_[0]or@_作为传递给子组件的值:
$a = sub { print "\$_=$_\n" ; print "\$_[0]=$_[0]\n" };
$a->(1);
# prints out
# $_=
# $_[0]=1
Run Code Online (Sandbox Code Playgroud)
请注意,在我的示例中$_不起作用,但$_[0](ie, @_) 起作用。Parallel::Loops示例中的 coderef 和我的示例中的 coderef 有什么不同?
请注意,他们的示例不是拼写错误:它仅在您使用时才有效$_,这就是我提出这个问题的原因。
当您想知道它是如何做它的事情时,请查看模块源代码:)
在 中Parallel::Loops::foreach,模块$_在调用您提供的子例程之前进行设置。由于这是一个分叉进程,因此它不会做任何事情来保护 的值$_。请注意该模块中的各个代码引用层。
# foreach is implemented via while above
sub foreach {
my ($self, $varRef, $arrayRef, $sub);
if (ref $_[1] eq 'ARRAY') {
($self, $arrayRef, $sub) = @_;
} else {
# Note that this second usage is not documented (and hence not
# supported). It isn't really useful, but this is how to use it just in
# case:
#
# my $foo;
# my %returnValues = $pl->foreach( \$foo, [ 0..9 ], sub {
# $foo => sqrt($foo);
# });
($self, $varRef, $arrayRef, $sub) = @_;
}
my $i = -1;
$self->while( sub { ++$i <= $#{$arrayRef} }, sub {
# Setup either $varRef or $_, if no such given before calling $sub->()
if ($varRef) {
$$varRef = $arrayRef->[$i];
} else {
$_ = $arrayRef->[$i];
}
$sub->();
});
}
Run Code Online (Sandbox Code Playgroud)
你也可以做同样的事情。每次要运行代码引用时,请设置$_第一个值:
for_all( [ qw(1 3 7) ], sub { print "$_\n" } );
sub for_all {
my( $array, $sub ) = @_;
foreach my $value ( @$array ) {
local $_ = $value;
$sub->();
}
}
Run Code Online (Sandbox Code Playgroud)
例如,看看Mojo::Collection ,它使用其代码引用来执行此操作。List::Util有几个实用程序也可以执行此操作。