2016-04-30 50 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