【问题标题】:Perl: share complex data-structure between threadsPerl:在线程之间共享复杂的数据结构
【发布时间】:2017-10-12 07:35:11
【问题描述】:

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

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

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

  • 有更好的方法吗?

  • 您更喜欢 JSON 还是 Storable 或其他方式?

感谢您的帮助!

编辑

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

【问题讨论】:

    标签: multithreading perl


    【解决方案1】:

    在处理这个问题时,我使用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 将您限制为数组/哈希数据结构 - 这可能适合您的用例。

    【讨论】:

      【解决方案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' ] };

      当为共享而填充数据结构时,如第一个示例所示,则需要支付的开销更少。否则会涉及到数据复制,如第二个示例所示,这是否可行取决于细节(数据大小、复制频率等)。

      序列化数据的想法也是可行的,但它的适用程度再次取决于细节,因为在这种情况下,您不仅会复制数据,还会复制到磁盘。

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

      另一种选择是使用工作模型并通过消息队列传递数据。然后你可以使用Thread::Queue,或者使用Thread::Queue::Any,作为沟通渠道。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-07-30
        • 2018-07-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-03-23
        • 2016-02-05
        相关资源
        最近更新 更多