Multithreading Perl:在线程之间共享复杂的数据结构

Multithreading Perl:在线程之间共享复杂的数据结构,multithreading,perl,Multithreading,Perl,我喜欢在线程之间共享复杂的数据结构。 据我所知,这是不可能的线程:共享(只有基本类型是可共享的) 因此,我考虑使用JSON或Storable对结构进行序列化/反序列化,以便它只是一个我可以完全共享的字符串。但是我需要在使用前把它拆开,更换后再打包 这是解决这个问题的常用方法吗 有更好的方法吗 您喜欢JSON、Storable还是其他 谢谢你的帮助 编辑 我只是用Storable和JSON做了一些测试。JSON更快,生成的序列化字符串更小。我没想到。复杂的数据结构可以使用共享。在添加到数据结构

我喜欢在线程之间共享复杂的数据结构。 据我所知,这是不可能的线程:共享(只有基本类型是可共享的)

因此,我考虑使用JSON或Storable对结构进行序列化/反序列化,以便它只是一个我可以完全共享的字符串。但是我需要在使用前把它拆开,更换后再打包

  • 这是解决这个问题的常用方法吗

  • 有更好的方法吗

  • 您喜欢JSON、Storable还是其他

谢谢你的帮助

编辑


我只是用Storable和JSON做了一些测试。JSON更快,生成的序列化字符串更小。我没想到。

复杂的数据结构可以使用共享。在添加到数据结构之前,需要克隆数据结构的组件

use strict;
use feature 'say';
use Data::Dump qw(dd);

use threads;
use threads::shared;

my $cds = {
    k1 => shared_clone( { k1_l2 => [ 1..2 ] } ),
    k2 => shared_clone( { k2_l2 => [10..11] } )
};

my @threads = map { async(\&proc_ds, $cds->{$_}) } keys %$cds;

$_->join() for @threads;

dd $cds;

sub proc_ds {
    my ($ds) = @_;
    lock $ds;
    push @{$ds->{$_}}, 10+threads->tid  for keys %$ds;
}
请注意,您不希望在使用共享值时允许自动激活,因为它会在结构中创建非共享(且为空)组件。明确检查是否存在

一个现成的数据结构需要被克隆和共享

my $cds = { k => [ 5..7 ] };          # already built, need be shared
my $cds_share = shared_clone( $cds );

my @threads = map { async(\&proc_ds, $cds_share) } 1..3;
$_->join() for @threads;
使用与上述相同的
proc_ds()
打印结构(压缩输出)

{'k'=>['5','6','7','11','12','13']}; 当数据结构被填充以进行共享时(如第一个示例中所示),那么支付的开销就更少了。否则会涉及数据拷贝,如第二个示例中所示,这是否正常取决于细节(数据大小、拷贝频率等)

序列化数据的想法也是可行的,但它的适用性又取决于细节,因为在这种情况下,您不仅要复制数据,而且还要将数据复制到磁盘

在这种情况下,JSON无疑是一种很好的方式,它是一种简单易读的数据格式,并且可以在工具之间共享。可存储是二进制的,可以直接与Perl数据结构一起工作,并且应该是快速的(在较大的数据中应该显示)


另一种选择是使用辅助模型并通过消息队列传递数据。然后,您将使用或可能使用通信通道。

在处理此问题时,我使用
Thread::Queue
传递对象,通常使用
Storable
进行序列化

我没有费心做性能比较,因为通常我的数据传递开销不是限制因素

请注意,
Storable
的主要优点是它允许一些有限的对象支持(不要-小心-它只在对象是自包含的情况下才起作用):

如果JSON将您限制为数组/散列数据结构,这对于您的用例来说可能很好

{ 'k' => [ '5', '6', '7', '11', '12', '13' ] };
#!/usr/bin/env perl
use strict;
use warnings;

package MyObject;

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

sub access_thing { 
   my ( $self ) = @_;
   return $self -> {access_count}++; 
}

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

package main; 

use threads;
use Thread::Queue;

use Storable qw ( freeze thaw );

my $thread_count = 10;

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

sub worker  {
   while ( my $item = $work_q -> dequeue ) {
      my $obj = thaw ( $item ); 
      print $obj -> get_id, ": ", $obj -> access_thing,"\n";    

   }
}

for (1..$thread_count) {
   threads -> create (\&worker); 
}

for my $id ( 0..1000 ) {
   my $obj = MyObject -> new ( $id ); 
   $work_q -> enqueue ( freeze ( $obj ) );
}

$work_q -> end;

$_ -> join for threads -> list;