2016-10-31 3 views
1

Je possède ce morceau de code que je voudrais paralléliser (pour référence):parallèle :: Forkmanager -> remplir un hachage de hachages de tableaux de l'enfant traite

my (%fastas, %counts); 

foreach my $sample (sort keys %AC2) 
{ 
    foreach my $chrom (sort keys %{ $AC2{$sample} }) 
    { 
     foreach my $pos (sort { $a <=> $b } (@{ $allAC2{$chrom} })) 
     { 
      my $allele; 

      #position was genotyped in sample 
      # or is AC=1, but was also found in AC=2 
      if(grep(/\b$pos\b/, @{ $AC2{$sample}{$chrom} }) || grep(/\b$pos\b/, @{ $finalAC1{$sample}{$chrom} })) #"\b" is for word boundary -> exact word match 
      { 
       $allele = @{ $vcfs{$sample}{$chrom}{$pos} }[2]; #ALT allele 
      } 
      #Make sure all SNP positions are in all samples 
      #Fill with reference genome allele information 
      else 
      { 
       #Fill with reference genome allele information 
       $allele = substr(@{ $ref{$chrom} }[0], $pos-1, 1); #or die "$sample, $chrom, $pos"; 
      } 
      push (@{ $fastas{$sample}{$chrom}{$pos} }, $allele); 
      push (@{ $counts{$chrom}{$pos} }, $allele) unless (grep {$_ eq $allele} @{ $counts{$chrom}{$pos} }); 
     } 
    } 
} 

Fondamentalement, les processus enfants ont besoin pour peupler les deux hachages. J'ai cherché et trouvé seulement quelques exemples montrant comment utiliser "run_on_finish" pour retourner la variable des processus fils. Le "problème" est que tous les exemples/tutoriels que j'ai trouvés retournent toujours des scalaires.

Est-il possible de passer un hachage (ou 2 hachages) hors du processus enfant?

Merci, Marco

+1

Les références sont des scalaires. – simbabque

+0

Voir: http://search.cpan.org/~yanick/Parallel-ForkManager-1.19/lib/Parallel/ForkManager.pm#Data_structure_retrieval PFM utilise Storable pour renvoyer les structures au processus parent. Le deuxième exemple montre l'enfant renvoyant des données arbitraires. –

+0

Étant donné que j'ai renvoyé une quantité importante de données, j'ai tendance à privilégier le modèle de type thread (worker) pour cela. Thread :: File d'attente et parallélisme. – Sobrique

Répondre

2

Ne pas retourner hash, retour des références de hachage.

Les références en Perl sont des valeurs scalaires. Donc, tout ce que vous devez faire est de renvoyer une référence à %fastas et %counts.

Voici un exemple hacky tiré de la documentation de Parallel :: Forkmanager. Il construit un hachage dans chaque processus enfant avec autant d'éléments que les données d'entrée le suggèrent. Il renvoie une référence à ce hachage au parent, où le rappel le récupère et l'insère dans la structure de données $overall.

use strict; 
use warnings; 
use Data::Printer; 
use Parallel::ForkManager; 

my $pm = Parallel::ForkManager->new(2); 

my $overall; # will hold all results in the parent 
$pm->run_on_finish(sub { 
    my ($pid, $exit_code, $ident, $exit_signal, $core_dump, $data_structure_reference) = @_; 

    $overall->{$pid} = $data_structure_reference; 
}); 

DATA_LOOP: 
foreach my $data (1 .. 10) { 
    # Forks and returns the pid for the child: 
    my $pid = $pm->start and next DATA_LOOP; 

    my %child_result = map { $_ => 1 } 1 .. $data; 

    $pm->finish(0, \%child_result); 
} 

$pm->wait_all_children; 
p $overall; 

La sortie ressemble à ceci:

\ { 
    1224 { 
     1 1 
    }, 
    1225 { 
     1 1, 
     2 1 
    }, 
    1226 { 
     1 1, 
     2 1, 
     3 1 
    }, 
    1228 { 
     1 1, 
     2 1, 
     3 1, 
     4 1 
    }, 
    1230 { 
     1 1, 
     2 1, 
     3 1, 
     4 1, 
     5 1 
    }, 
    1231 { 
     1 1, 
     2 1, 
     3 1, 
     4 1, 
     5 1, 
     6 1 
    }, 
    1232 { 
     1 1, 
     2 1, 
     3 1, 
     4 1, 
     5 1, 
     6 1, 
     7 1 
    }, 
    1233 { 
     1 1, 
     2 1, 
     3 1, 
     4 1, 
     5 1, 
     6 1, 
     7 1, 
     8 1 
    }, 
    1234 { 
     1 1, 
     2 1, 
     3 1, 
     4 1, 
     5 1, 
     6 1, 
     7 1, 
     8 1, 
     9 1 
    }, 
    1235 { 
     1 1, 
     2 1, 
     3 1, 
     4 1, 
     5 1, 
     6 1, 
     7 1, 
     8 1, 
     9 1, 
     10 1 
    } 
} 

Si vous voulez retourner deux structures de données, les envelopper dans une référence de tableau.

$pm->finish(0, [ \%fastas, \%counts ]); 
2

Je pensais juste que je de publier ma solution:

my (%fastas, %counts); 

#setting up the forking process 
my $nCPU = Sys::CPU::cpu_count(); 
my $pm = Parallel::ForkManager -> new($nCPU); 

$pm->run_on_finish(sub { 
    my ($pid, $exit_code, $ident, $exit_signal, $core_dump, $data_structure_reference) = @_; 

    %fastas = (%fastas, %{ $data_structure_reference->{fas} }); 
}); 

my @mySamples = sort keys %AC2; 
my $s = $mySamples[0]; 

foreach my $sample (@mySamples) 
{ 
    my $pid = $pm->start and next; 

    my %allSeqs; 

    foreach my $chrom (sort keys %{ $AC2{$sample} }) 
    { 
     foreach my $pos (sort { $a <=> $b } (@{ $allAC2{$chrom} })) 
     { 
      my $allele; 

      #position was genotyped in sample 
      # or is AC=1, but was also found in AC=2 
      if(grep(/\b$pos\b/, @{ $AC2{$sample}{$chrom} }) || grep(/\b$pos\b/, @{ $finalAC1{$sample}{$chrom} })) #"\b is for word boundary -> exact word match" 
      { 
       $allele = @{ $vcfs{$sample}{$chrom}{$pos} }[2]; #ALT allele 
      } 
      #Make sure all SNP positions are in all samples 
      #Fill with reference genome allele information 
      else 
      { 
       #Fill with reference genome allele information 
       $allele = substr(@{ $ref{$chrom} }[0], $pos-1, 1); #or die "$sample, $chrom, $pos"; 
      } 

      push (@{ $allSeqs{$sample}{$chrom}{$pos} }, $allele); 
     } 
    } 
    $pm -> finish(0, { fas => \%allSeqs }); 
} 

$pm -> wait_all_children(); 


#List ALT alleles found at each position 
foreach my $sample (sort keys %fastas) 
{ 
    foreach my $chrom (sort keys %{ $fastas{$sample} }) 
    { 
     foreach my $pos (sort keys %{ $fastas{$sample}{$chrom} }) 
     { 
      my $allele = @{ $fastas{$sample}{$chrom}{$pos} }[0]; 
      push (@{ $counts{$chrom}{$pos} }, $allele) unless (grep {$_ eq $allele} @{ $counts{$chrom}{$pos} }); 
     } 
    } 
} 

J'ai dû enlever% que les chiffres de la boucle principale et calculer séparément, car il devait se référer à ses propres valeurs (du processus parent) tout en étant processus dans les processus de l'enfant (j'espère que cette explication a du sens!).

Merci pour l'aide tout le monde, j'ai été très apprécié! Marco