我的脚本有对象哈希 - 所有单个类(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并且答案不能满足我的要求。
请让我知道你的想法。
答案 0 :(得分:1)
这是因为Perl本身并不在线程之间共享对象 - 或者其他任何东西。当Thread2启动时,它会获得当时程序状态的副本,并从那里开始。因此,如果Thread1在创建Thread2之后更改任何值,则此更改仅对Thread1可见。
现在,有几种方法可以解决这个问题。正如@Borodin所提到的,您可以使用外部库来为您处理数据交换。如果您不想依赖外部库,或者由于某种原因无法安装它,您可以通过在它们之间使用某些东西来共享这些数据来自己完成 - 比如临时系统文件或数据库。它并不像听起来那么复杂,我们已经在我的公司实现了它,它运作得很好。
threads::shared
已经成为核心Perl模块已经有一段时间......
答案 1 :(得分:1)
我建议首先分享一个对象不是一个好主意 - 它可以用threads::shared
来完成,但是有一些限制,你可能会引入一些竞争条件。
相反,我会说 - 使用Thread::Queue
在线程之间进行通信,并使用Storable
与freeze
和thaw
序列化。
这是一个有点简单的例子,但希望说明一点?那是你不是"分享"对象,而只是将它们作为序列化数据结构传递。如果实例化对象进行系统状态更改(例如打开与数据库或类似的连接),它会稍微分解 - 但这在线程上下文中本身就很难做到。
#!/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";
}