2013-07-17 50 views
2

我試圖將子例程引用傳遞給perl線程來實現threadMap子例程。我處於一個我必須「自我推銷」大多數事物的環境中;安裝新的perl軟件包不是一種選擇。將子例程引用傳遞給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 $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; 
} 

當我運行這個所謂的 '富' 擁有大約如下腳本:

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代碼(0xbf3530)

我有f代碼(0xbf3530)

我爲L < 1>和f CODE(0x110f100)

線程1異常終止:未定義子程序&主::˚F在/ U稱爲 /傑米/perl/jdPerlLib.pl線6037

餘爲L < 2>和f CODE異常終止(0x16b3df0)

線程2:未定義子程序&主::˚F在/ U稱爲 /傑米/perl/jdPerlLib.pl線6037

我有大號< 3>和f CODE(0x1a7d7b0)

線程3異常終止:未定義子程序&主::˚F在/u/jamie/perl/jdPerlLib.pl線稱爲

我爲L < 4 >和f CODE(0x1fbb600)

螺紋4異常終止:未定義子程序&主::˚F稱爲 在/u/jamie/perl/jdPerlLib.pl線6037

我爲L < 5>和f代碼(0x7 fd5240b78c0)

螺紋5異常終止:未定義子程序&主::˚F在/u/jamie/perl/jdPerlLib.pl線6037稱爲 。

星期三07月17日10時27分49秒2013:我有輸入< 1 2 3 4 5>和輸出<>

這告訴我,功能參考是恆定的,從foo到頂部我線程映射子程序,但是一旦它被傳遞給線程,它就會被改變並且變得不合時宜。爲什麼是這樣?我可以避免它嗎?

注意,它無法與兩個

#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[$_])); 

而且,因爲這是我的第一篇到計算器,很清楚我的問題不夠,或過於/不夠詳細?

+0

更新 - 如果我的測試程序「foo」具有以下內容,則它會顯示工作: sub f {$ i)= @_;返回100 * $ i; } my $ f = \&f; 這提示了一個可能的解釋 - perl使匿名子例程引用SOMEWHERE的淺拷貝不在它是否是對'真實'子例程的引用?但我仍然不清楚細節......任何'指針'(har!)? –

回答

3

要調用一個名爲「F」裏面threadMap功能:

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

其功能,作爲錯誤信息表明,不存在。

你的意思是取消引用和調用的CODEREF代替:

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

在你更新的評論,代碼工作,因爲有你定義了一個名爲「F」子。

另外,你一般應該用而不是用和號sigil調用perl subs。這是來自perl 4的保留語法,並且在perl 5中具有非常特定的語義,當你僅僅需要調用子程序時幾乎不需要它。

調用&f將禁用原型處理,並且可以傳遞@_ - 如果該行爲似乎對您沒有直接用處,則不要使用該功能。當表示子本身(例如,my $coderef = \&fdefined &f)和特殊goto &f調用時也使用&&也會取消引用CODE ref,通常用於引用它,但該操作更明顯地用箭頭和圓括號表示:$coderef->()

+0

Pilcrow:謝謝您的詳細回覆。好眼睛重新:我的錯字。謝謝。我也很感謝你提出的改進$ coderef - >(),並且適當地修改了我的Perl代碼中的相關子例程。 TMTOWTDI,但很適合使用模糊的最新技術。我認爲我的perl書是爲perl寫的4。 –

相關問題