2017-10-12 7 views
3

J'aime partager une structure de données complexes entre threads. Jusqu'à présent, je sais que ce n'est pas possible avec les threads: partagé (seuls les types de base sont partageables).Perl: partager la structure de données complexe entre les threads

Donc je pense à sérialiser/désérialiser la structure avec JSON ou Storable donc c'est juste une chaîne que je peux partager parfaitement. Mais je dois le déballer avant de l'utiliser et l'emballer après un changement.

  • Est-ce une façon courante de travailler sur ce problème?

  • Y a-t-il de meilleurs moyens?

  • Si vous préférez JSON ou Storable ou autre chose?

Merci pour votre aide!

EDIT

Je viens de faire quelques tests avec stockable et JSON. JSON est plus rapide et produit des chaînes sérialisées plus petites. Je ne m'attendais pas à ça.

+0

Vous pouvez partager des structures de données complexes en utilisant 'shared_clone', mais vous devez ensuite cloner les composants avant de les ajouter à la structure (vous ne pouvez pas" partager "le ready). Est-ce approprié? – zdim

+0

Dans le cas où cela est tombé à travers les fissures, voir [Que dois-je faire quand quelqu'un répond à ma question?] (Http://stackoverflow.com/help/someone-answers) – zdim

Répondre

2

Les structures de données complexes peuvent être partagées en utilisant shared_clone. Les composants de la structure de données doivent être clonés avant d'y être ajoutés.

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

Si vous avez une structure de données prête alors cela ne peut en effet pas être simplement partagé.

Notez que vous ne souhaitez pas autoriser l'autovivification lorsque vous utilisez des valeurs partagées, car cela créerait des composants non partagés (et vides) dans la structure. Vérifiez explicitement l'existence.


Peut-être plus au point ici

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; 

Avec le même proc_ds() comme ci-dessus cette imprime la structure (sortie condensée)

 
{ 'k' => [ '5', '6', '7', '11', '12', '13' ] }; 
+0

@ chris01 Ajout d'un exemple qui peut être plus pertinent – zdim

2

En traitant ce problème, j'utilise Thread::Queue pour passer mes objets autour, et utilise habituellement Storable pour sérialiser.

Je n'ai pas pris la peine de faire des comparaisons de performances, car habituellement mon temps de transfert de données n'est pas le facteur limitant.

Note - le principal avantage de Storable est qu'il permet un soutien d'objet limité (Non - attention - il que fonctionne que si votre objet est autonome):

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

Si JSON voulez-vous limiter aux structures de données array/hash - ce qui peut convenir à votre cas d'utilisation.