2017-10-12 153 views
3

我喜歡在線程之間共享複雜數據結構。 據我所知,這是不可能的線程:共享(只有基本類型是可共享的)。Perl:在線程之間共享複雜數據結構

所以我想用JSON或Storable對序列化/反序列化結構,所以它只是一個字符串,我可以完美地共享。但是我需要在使用前將其打開並在更改後將其打包。

  • 這是一種常見的解決方法嗎?

  • 有沒有更好的方法?

  • 您是否更喜歡JSON或可存儲或其他?

感謝您的幫助!

編輯

我只是做了一些測試與可存儲和JSON。 JSON更快,生成更小的序列化字符串。我原本沒想到。

+0

您可以使用'shared_clone'共享複雜的數據結構,但是您需要在將組件添加到結構之前克隆組件(無法「共享」現成的組件)。那是合適的嗎? – zdim

+0

如果發生這種情況,請參閱[當某人回答我的問題時該怎麼辦?](http://stackoverflow.com/help/someone-answers) – zdim

回答

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

@ chris01添加了一個可能更重要的示例 – zdim

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會限制你到數組/散列數據結構 - 這可能適合您的使用情況。