【问题标题】:Passing subroutine references to perl threads将子例程引用传递给 perl 线程
【发布时间】:2013-07-17 14:47:54
【问题描述】:

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

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

我可以毫无问题地传递子程序引用。但是,一旦我尝试将子例程引用传递给线程,线程似乎并不理解它。

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

#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 $f\n"; return (map{ &f($_) } @{$L}) }, ($threadLists[$_],$f) );
  push @threads, threads->create({'context' => 'list'}, sub{ my ($L) = @_; print "I have L <@$L> and f $f\n"; 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 $f\n";

@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 CODE(0xbf3530)

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

我有 L 和 f CODE(0x110f100)

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

我有 L 和 f CODE(0x16b3df0)

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

我有 L 和 f CODE(0x1a7d7b0)

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

我有 L 和 f CODE(0x1fbb600)

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

我有 L 和 f CODE(0x7fd5240b78c0)

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

2013 年 7 月 17 日星期三 10:27:49:我有输入 和输出

这告诉我函数引用从 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 $f\n"; return (map{ &f($_) } @{$L}) }, ($threadLists[$_],$f) );
  push @threads, threads->create({'context' => 'list'}, sub{ my ($L) = @_; print "I have L <@$L> and f $f\n"; 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 $f\n"; return (map{ &f($_) } @{$L}) }, ($threadLists[$_],$f) );
  #push @threads, threads->create({'context' => 'list'}, sub{ my ($L) = @_; print "I have L <@$L> and f $f\n"; return (map{ &f($_) } @{$L}) }, ($threadLists[$_]) );

另外,由于这是我在 stackoverflow 上的第一篇文章,我的问题是否足够清楚,或者太/不够冗长?

【问题讨论】:

  • 更新——如果我的测试程序 'foo' 具有以下内容,它似乎可以工作: sub f{ my ($i) = @_;返回 100*$i; } 我的 $f = \&f;这提出了一个可能的解释——perl 对匿名子例程引用做了一个浅拷贝,如果它是对“真实”子例程的引用,它不会?但我仍然不清楚细节......任何“指针”(har!)?

标签: multithreading perl reference subroutine


【解决方案1】:

你在threadMap中调用了一个名为“f”的函数:

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

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

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

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

在您的更新评论中,代码有效,因为您确实在其中定义了一个名为“f”的子。

顺便说一句,您通常应该使用 & 符号调用 perl subs。这是 perl 4 中的保留语法,并且在 perl 5 中具有非常特定的语义,当您只想调用 sub 时几乎不需要这些语义。

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

【讨论】:

  • Pilcrow:感谢您的详细回复。好眼睛回复:我的错字。谢谢。我也很欣赏你建议的改进 $coderef->() 并适当地修改了我的 perl 代码中的相关子例程。 TMTOWTDI,但最好使用模糊的最新技术。我认为我的 perl 书是为 perl 4 编写的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-09
  • 2011-02-01
  • 1970-01-01
  • 2021-04-03
  • 2012-05-30
相关资源
最近更新 更多