2016-04-30 13 views
1

ファイルを読み込んでPerlでデータを解析するコードを最適化しようとしています。Perl:複数のスレッドを使用して複雑なオブジェクトツリーを構築する

背景

  • データは、複雑なオブジェクトツリーで終わります。
  • トップレベルのオブジェクトは、祝福されたパッケージです。
  • ネストされたオブジェクトのいくつかは、別の祝福されたパッケージタイプの呼び出しアイテムとしてnew'edされます。
  • 最初のパスでは、バイナリデータをユニット内で区切り、ユニット内で複数の配列にすべて格納されているユニット を区切ります。
  • それぞれ8つのセグメントで20または50のユニットが存在する可能性があります。
  • 2番目のパスはバイナリデータのデコードを実行し、速度のために最適化が必要なものです。スレッド

    アプローチ私は共有::モジュールのスレッドとスレッドを使用しようとしています。

  • 私は、各スレッドがユニットのサブセットを処理し、共通のオブジェクトツリーにデータを移入させたいと思います。

私は、スレッドコンテキストから割り当てられ、祝福され、共有オブジェクトツリーに挿入される祝福オブジェクトを共有する方法を示すサンプルコードを探しています。そして、データ検索のためにデータを歩くためにメインスレッドからアクセスできます。デコードが完了すると、デコードスレッドが復帰します。

  • スレッド:共有モジュールを使用して複数のスレッドにオブジェクトを共通のオブジェクトツリーに挿入する方法がわかりません。特にItem型のオブジェクトがスレッドコンテキストから祝福されている場合クラス(パッケージ)関数は私が理解しているようにオブジェクトにバインドされません。
  • 私は、オブジェクトツリーにオブジェクトを追加する前にコードのthreads :: shared :: lock()関数を使用する必要があることを認識しています。
  • 特に、ネストされたblessed Itemオブジェクトは、各スレッドコンテキストから割り当てられます。
  • threads :: sharedのドキュメントには、「クラス自体が共有をサポートするように書かれていない限り、オブジェクトを共有することはしばしば賢明ではないことに注意してください。
    • これを実現する方法を示すサンプルコードはありますか?

ドキュメントも「オブジェクトのデストラクタは、各スレッドのスコープ出口のための1つの複数回呼び出されるかもしれません」と言います。どのようにこれは適切に処理されますか?

おかげので、少しバックトラック J.R.

答えて

3

OK、 - threads::sharedが本当に「単一のデータ構造」を行い、実際にはもっと複雑なものをサポートしていません。なぜなら、あなたが「スレッド」のときには、(いくつかの)共有メモリ空間を持つ別々のプログラムインスタンスを実際に作成しますが、実際にはそれぞれの「スレッド」は別のプログラムです。

したがって、オブジェクトの共有をサポートすることは本当に面倒です。私はよりよいアプローチが...ないことを発見しました。 Thread::Queueを使用してスレッド間でデータを渡し、結果を照合する1つのスレッドを使用します。より複雑なデータ構造を渡す必要がある場合は、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のバグと制限事項を参照してください。 オブジェクトを含む配列/ハッシュ・リファレンスを渡すと、5.10.0より前のPerlでは機能しないことがあります。私は祝福された物と同じ制限があるように見えます。また、このアプリケーションは残念ながらPerl 5.8.8上にあります。 –

+0

このコメントエディタを使用して改行を行う方法を理解できません。 –

+0

オブジェクトを渡していません。シリアル化されたオブジェクトをスカラーとして渡しています。 – Sobrique

関連する問題