Perl - 如何在线程之间共享对象

时间:2017-11-09 09:50:23

标签: multithreading perl oop object

我的脚本有对象哈希 - 所有单个类(SampleClass.pm)。以下是我用来创建对象的方式。

$objectHash{'foo'} = SampleClass->new();
$objectHash{'bar'} = SampleClass->new();
.
.

然后我产生了几个线程(比如说5),每个线程按照指示完成它的工作。

现在说线程1写入对象 -

$objectHash{'foo'}->settimeWhenISaidHello($time);

并退出。现在,当Thread2开始工作并检查如下所示的值时

$lastHelloTime = $objectHash{'foo'}->gettimeWhenISaidHello($time);

它得到未定义或空值。我想在线程之间共享这些值。怎么可能?

另外,我的类构造函数new将散列和散列数组作为成员变量,如下所示。

sub new
{
.
.
listOfGuysToSayHello = {}; #This is an array with guy name as key and array value as data
SchoolsWithStudentsToSayHellow = {}; #this is array of hashes
.
.
}

此外,我已经完成了这个问题 - how to access perl objects in threads并且答案不能满足我的要求。

请让我知道你的想法。

2 个答案:

答案 0 :(得分:1)

这是因为Perl本身并不在线程之间共享对象 - 或者其他任何东西。当Thread2启动时,它会获得当时程序状态的副本,并从那里开始。因此,如果Thread1在创建Thread2之后更改任何值,则此更改仅对Thread1可见。

现在,有几种方法可以解决这个问题。正如@Borodin所提到的,您可以使用外部库来为您处理数据交换。如果您不想依赖外部库,或者由于某种原因无法安装它,您可以通过在它们之间使用某些东西来共享这些数据来自己完成 - 比如临时系统文件或数据库。它并不像听起来那么复杂,我们已经在我的公司实现了它,它运作得很好。

编辑:正如@PerlDuck巧妙地指出的那样,threads::shared已经成为核心Perl模块已经有一段时间......

答案 1 :(得分:1)

我建议首先分享一个对象不是一个好主意 - 它可以用threads::shared来完成,但是有一些限制,你可能会引入一些竞争条件。

相反,我会说 - 使用Thread::Queue在线程之间进行通信,并使用Storablefreezethaw序列化。

这是一个有点简单的例子,但希望说明一点?那是你不是"分享"对象,而只是将它们作为序列化数据结构传递。如果实例化对象进行系统状态更改(例如打开与数据库或类似的连接),它会稍微分解 - 但这在线程上下文中本身就很难做到。

#!/usr/bin/env perl

use strict;
use warnings;

package MyObject;

sub new {
   my ( $class, %args ) = @_;
   my $self = \%args;
   bless $self, $class;
   return $self;
}

sub get_value {
   my ( $self, $key ) = @_;
   return $self->{$key} // 0;
}

sub set_value {
   my ( $self, $key, $value ) = @_;
   $self->{$key} = $value;
}

package main;

use threads;
use Storable qw ( freeze thaw );
use Thread::Queue;

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

sub worker {
   while ( my $serialised = $work_q->dequeue ) {
      my $local_obj = thaw $serialised;
      print threads->self->tid, " is processing object with id ",
        $local_obj->get_value('id'), "\n";
      $local_obj->set_value( 'processed_by', threads->self->tid );
      $result_q->enqueue( freeze $local_obj );
   }
}

threads->create( \&worker ) for 1 .. 10;

for ( 1 .. 100 ) {
   my $obj = MyObject->new( id => $_ );
   $work_q->enqueue( freeze $obj );
}
$work_q->end;
$_->join for threads->list;

while ( my $ser_obj = $result_q->dequeue_nb ) {
   my $result_obj = thaw $ser_obj;
   print "Object with ID of :", $result_obj->get_value('id'),
     " was processed by thread ", $result_obj->get_value('processed_by'),
     "\n";
}