2016-04-30 49 views
1

我想優化加載文件並在Perl中解析數​​據的代碼。Perl:使用多線程構建複雜對象樹

背景

  • 的數據在一個複雜的對象樹結束。
  • 頂層對象是一個有福的包。
  • 一些嵌套對象被new'ed作爲另一個有福的包類型調用Item。
  • 第一遍將二進制數據分離爲一個單元,並將這些單元分段存儲在一個單元中,這些單元都存儲在多個數組中。
  • 可能有20個或50個單元,每個單元8個。
  • 第二遍執行二進制數據的解碼,並且是需要針對速度進行優化的。

引橋線程

  • 我想使用的模塊線程和線程::共享。
  • 我希望每個線程處理單元的一個子集並將數據填充到通用對象樹中。

我在查找一些示例代碼,演示如何共享可以從任何線程上下文中分配和祝福的祝福對象,並將其插入到共享對象樹中。然後可以從主線程訪問數據以查找數據。一旦解碼完成,解碼線程將返回。

  • 我很難看到如何讓多個線程使用線程:共享模塊插入對象到公共對象樹。特別是當Item類型的對象從線程上下文中獲得祝福時。據我所知,類(包)函數不會綁定到對象。
  • 我知道,在代碼中的某些點上,代碼在將對象添加到對象樹之前需要使用threads :: shared :: lock()函數。
  • 特別是嵌套的祝福的Item對象將從每個線程上下文中分配。
  • threads :: shared文件說:「請注意,共享對象往往不明智,除非類已經被寫入支持共享。
    • 是否有示例代碼演示如何完成此操作?

的文檔還寫着「對象的析構函數可以被調用多次,每個線程的範圍退出」。這是如何正確處理的?

感謝 J.R.

回答

3

好了,回溯了一下 - threads::shared確實「單一數據結構」並沒有真正支持更復雜的東西。這是因爲當你'線程'時,你實際上創建了具有(某些)共享內存空間的獨立程序實例,但實際上每個'線程'都是一個單獨的程序。

因此,支持共享一個對象變得非常混亂。我發現更好的方法是......不是。使用Thread::Queue在線程之間傳遞數據,並有一個線程用於整理結果。如果您需要傳遞更復雜的數據結構,則可以使用Storablefreeze/thaw來串行化對象,並使用enqueue它。

這樣你就不必擔心跳過共享嵌套數據結構 - 而且很有可能你會這樣做,因爲在對象上沒有「深度共享」選項 - 你必須明確地使用share每個內部數組/散列(引用)。

所以我會解決它像這樣:

#!/usr/bin/perl 
use strict; 
use warnings; 

package Test_Object; 

sub new { 
    my ($class, $id) = @_; 
    my $self = {}; 
    $self->{id} = $id; 
    bless $self, $class; 
    return $self; 
} 

sub set_result { 
    my ($self, $result_code) = @_; 
    $self->{result} = $result_code; 
} 

sub get_id { 
    my ($self) = @_; 
    return $self->{id}; 
} 

sub get_result { 
    my ($self) = @_; 
    return $self->{result}; 
} 

package main; 

use strict; 
use warnings qw/ all /; 

use threads; 
use Thread::Queue; 
use Storable qw/ freeze thaw/; 

my $work_q = Thread::Queue->new(); 
my $result_q = Thread::Queue->new(); 

sub worker { 
    my $tid = threads->self->tid; 
    print "$tid: starting\n"; 
    while (my $item = $work_q->dequeue()) { 
     my $object = thaw($item); 
     print "$tid: got object with ID of ", $object->get_id, "\n"; 
     $object->set_result($object->get_id . " : $tid"); 
     $result_q->enqueue(freeze $object); 
    } 
} 

sub collator { 
    while (my $result = $result_q->dequeue) { 
     my $object = thaw $result; 
     print "Collator got object with result code of ", $object->get_result, 
     "\n"; 
    } 

    ## do something with collated wossnames - pass back to main maybe? 
} 

my @workers; 
for (1 .. 5) { 
    my $thr = threads->create(\&worker); 
    push @workers, $thr; 
} 

my $collator = threads->create(\&collator); 

for (1 .. 200) { 
    my $work_object = Test_Object->new($_); 
    $work_q->enqueue(freeze $work_object); 
} 

$work_q->end; 
foreach my $thr (@workers) { 
    $thr->join; 
} 

$result_q->end; 
foreach my $thr (threads->list) { 
    $thr->join; 
} 
+0

我很欣賞的響應。 「Thread :: Queue」的文檔說如果對象的類不支持共享,則在隊列上傳遞對象可能不起作用。有關更多信息,請參閱threads :: shared中的BUGS AND LIMITATIONS。 傳遞包含對象的數組/散列引用對於5.10.0之前的Perl可能無效。它看起來像我與我受祝福的物體一樣的限制。不幸的是,這個應用程序仍然在Perl 5.8.8上。 –

+0

無法弄清楚如何使用此評論編輯器製作換行符。 –

+0

你沒有傳遞對象。您將序列化對象作爲標量傳遞。 – Sobrique