将子例程引用传递到perl线程



我正试图将子例程引用传递给perl线程,以实现threadMap子例程。我所处的环境中,大多数事情我都必须"自己做";安装新的perl包不是一种选择。

此外,我正在运行perl版本5.10。在我的工作环境中,perl>5.10的版本不可用。

我可以毫不费力地传递子程序引用。然而,一旦我试图将子例程引用传递给线程,该线程似乎就无法理解它

这是我提出的threadMap子程序,我相信它的注释对于感兴趣的问答者来说是足够解释的。

#input: hash with keys L (listref), f (function which can apply to each element of L), and optionally nThreads
#default for nThreads is 50
#divides L into sublists for each thread, then kicks off threads
#each thread applies f to each element of the sublist
#and then returns the result of $f on each item
#output: map{ &$f($_) } @{$L}, but done threadily
sub threadMap{
  my %arg = @_;
  my ($L,$f,$nThr) = ($arg{L},$arg{f},$arg{nThreads});
  my $MAXTHREADS = 50;
  if(not defined $nThr or $nThr > $MAXTHREADS){
   $nThr = $MAXTHREADS;
  }
  &log(1,"threadMap: I have f $f");
  my @threadLists = &makeSublistsForThreads($L,$nThr);
  #in the event that L is less than $nThr, we reduce the number of threads
  $nThr = scalar(@threadLists);
  my @threads; 
  my @ret;
  for(0 .. $nThr-1){
  #invoke the threads in list context
  #    push @threads, threads->create({'context' => 'list'}, sub{ my ($L,$f) = @_; print "I have L <@$L> and f $fn"; return (map{ &f($_) } @{$L}) }, ($threadLists[$_],$f) );
  push @threads, threads->create({'context' => 'list'}, sub{ my ($L) = @_; print "I have L <@$L> and f $fn"; return (map{ &f($_) } @{$L}) }, ($threadLists[$_]) );
  }
  for(@threads){
  #each thread returns its items, so we get them back in order
      push @ret, $_->join();
  }
  return @ret;
}

当我运行这个名为"foo"的脚本时,它大约有以下内容:

my @L = (1 .. 5); 
my $f = sub{ my ($i) = @_; return 100*$i; };
print "I have f $fn";
@out = &threadMap("L"=>@L,"f"=>$f);
&log(1,"I had input <@L> and output <@out>");
my @realOut = map{ &$f($_) } @L; 
&log(1,"Output should be <@realOut>");

我得到这个输出:

我有f代码(0xbf3530)

2013年7月17日星期三10:27:49:线程映射:我有f代码(0xbf3530)

我有L<1> 和f代码(0x110f100)

线程1异常终止:未定义的子例程&main::f调用在/u/jamie/perl/jdPerlLib.pl行6037。

我有L<2> 和f代码(0x16b3df0)

线程2异常终止:未定义的子例程&main::f调用在/u/jamie/perl/jdPerlLib.pl行6037。

我有L<3> 和f代码(0x1a7d7b0)

线程3异常终止:未定义的子例程&main::f调用在/u/jamie/perl/jdPerlLib.pl行6037。

我有L<4> 和f代码(0x1fbb600)

线程4异常终止:未定义的子例程&main::f调用在/u/jamie/perl/jdPerlLib.pl行6037。

我有L<5> 和f代码(0x7fd5240b78c0)

线程5异常终止:未定义的子例程&main::f调用在/u/jamie/perl/jdPerlLib.pl行6037。

2013年7月17日星期三10:27:49:我有输入<1 2 3 4 5>并且输出<>

这告诉我,从foo到threadMap子例程的顶部,函数引用是恒定的,但一旦它被传递到线程,它就会被更改并失控。为什么会这样?我能避开它吗?

请注意,它在两个中都失败了

  #invoke the threads in list context
  #    push @threads, threads->create({'context' => 'list'}, sub{ my ($L,$f) = @_; print "I have L <@$L> and f $fn"; return (map{ &f($_) } @{$L}) }, ($threadLists[$_],$f) );
  push @threads, threads->create({'context' => 'list'}, sub{ my ($L) = @_; print "I have L <@$L> and f $fn"; return (map{ &f($_) } @{$L}) }, ($threadLists[$_]) );

  #invoke the threads in list context
      push @threads, threads->create({'context' => 'list'}, sub{ my ($L,$f) = @_; print "I have L <@$L> and f $fn"; return (map{ &f($_) } @{$L}) }, ($threadLists[$_],$f) );
  #push @threads, threads->create({'context' => 'list'}, sub{ my ($L) = @_; print "I have L <@$L> and f $fn"; return (map{ &f($_) } @{$L}) }, ($threadLists[$_]) );

此外,由于这是我第一次向stackoverflow发帖,我的问题是否足够清楚,或者过于/不够详细?

您正在threadMap:内部调用一个名为"f"的函数

map{ &f($_) } ...

如错误消息所示,该函数不存在。

您的意思是取消引用并调用CODEref:

map { $f->($_) } ...

在您的更新注释中,代码之所以有效,是因为您确实定义了一个名为"f"的子代码。

顺便说一句,您通常应该而不是用amp和sigil调用perl-subs。这是来自perl4的保留语法,并且在perl5中具有非常特定的语义,当您只想调用sub-时,这些语义几乎是不需要的

调用&f将禁用原型处理,并且可以传递@_——如果这种行为对您来说没有立即用处,那么就不要使用该功能。&也用于表示子本身(例如my $coderef = &fdefined &f)和特殊的goto &f调用。&还取消引用CODE ref,通常是为了调用它,但该操作更明显地是用箭头和圆括号表示的:$coderef->()

最新更新