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

时间:2017-10-12 07:35:11

标签: multithreading perl

我喜欢在线程之间共享复杂的数据结构。 据我所知,线程无法实现:共享(只有基本类型可共享)。

所以我想用JSON或Storable序列化/反序列化结构,所以它只是一个我可以完美分享的字符串。但我需要在使用前将其打开并在更换后打包。

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

  • 有更好的方法吗?

  • 您更喜欢JSON还是Storable或其他什么?

感谢您的帮助!

修改

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

2 个答案:

答案 0 :(得分:2)

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

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' ] };

答案 1 :(得分:2)

在处理此问题时,我使用Thread::Queue传递我的对象,并且通常使用Storable来序列化。

我没有打扰进行性能比较,因为通常我的数据传递开销不是限制因素。

注意 - Storable的主要优点是它允许一些有限的对象支持(不要 - 小心 - 如果对象是自包含的,可以工作):

#!/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; 

如果JSON限制您使用数组/哈希数据结构 - 这可能适用于您的用例。