PERL - Communication processus pere/fils

PERL - Communication processus pere/fils - Perl - Programmation

Marsh Posté le 13-12-2011 à 09:43:40    

Bonjour,
 
La, je bloque vraiment.  :??:  
Je fait un code qui utilise Parallel:ForkManager afin de pouvoir lancer des processus fils.
Ce que je voudrai, c'est que mes processus fils puissent modifier (en fait supprimer une case) un tableau qui est dans le main().
 
J'ai vu ces deux sujets:
ici et la
 
Mais je n'y comprend pas grand chose. Ces bibliothèques sont bien complexe.  :whistle:  
 
Exemple de ce que je souhaiterai:

Code :
  1. #!/opt/perl/bin/perl
  2. use strict;
  3. use warnings;
  4. use ForkManager;
  5. my $pm = Parallel::ForkManager->new(10);        #nombre de processus max
  6. $pm->run_on_finish( sub {
  7.     printf "%s : Process completed: @_\n", scalar localtime
  8. });
  9. my @tableau1=(1,2,3,4,5,6,7,8,9);
  10. while(@tableau1 n'est pas vide) {
  11. foreach(@tableau1){
  12.     $pm->start($i) and next;
  13.     supprimer l'element en cours de lecture de @tableau1
  14.     $pm->finish;
  15. }
  16. }
  17. printf "%s: Waiting for some child to finish\n", scalar localtime;
  18. $pm->wait_all_children;
  19. printf "%s: All processes finished.\n", scalar localtime;


 
Si quelqu'un arrive a trouver une solution a ce probleme, je lui en serait vraiment reconnaissant.  :wahoo:  
(Sachant que je ne peux pas utiliser la communication par fichier car ce ne serait pas "suffisamment propre".)
Cordialement,
Benjamin
 
PS:
Si quelqu’un est curieux de savoir les raison de ces questions:
J’essaie de mettre en place un multi thread sur le code suivant.
Ce code simule un démarrage de Jobs de façon hiérarchisé.
Donc le code suivant fonctionne mais j'aimerai maintenant y appliquer du multi thread lors du démarrage des jobs (actuellement simulé par un "sleep rand 5;" )via la bibliothèque ForkManager.

Code :
  1. #!/usr/bin/perl -w
  2. use strict;
  3. use warnings;
  4. use diagnostics;
  5. use Data::Dumper;
  6. use Parallel::ForkManager;
  7. ####################### PACKAGES ###########################
  8. package Job;
  9. my @listJob = ();
  10. my @tabProc = ();
  11. sub new {
  12.    my ($class, $ID_PROCESS, $ALIAS, $PERE, $FILS, $LOCK, $TYPE, $STARTED) = @_;
  13.    my $this = {};
  14.    bless($this, $class);
  15.  
  16.    $this->{ID_PROCESS} = $ID_PROCESS;
  17.    $this->{ALIAS} = $ALIAS;
  18.    $this->{PERE} = $PERE;
  19.    $this->{FILS} = $FILS;
  20.    $this->{LOCK} = $LOCK;
  21.    $this->{TYPE} = $TYPE;
  22.    $this->{STARTED} = $STARTED;
  23.  
  24.  
  25.   push(@listJob,$ID_PROCESS); 
  26.   push(@tabProc,$this);
  27. return $this;
  28.    }
  29.  
  30.  
  31. sub getID {
  32. my ($this) = @_;
  33. return $this->{ID_PROCESS};
  34. }
  35. sub getAlias {
  36. my ($this) = @_;
  37. return $this->{ALIAS};
  38. }
  39. sub getPere {
  40. my ($this) = @_;
  41. return $this->{PERE};
  42. }
  43. sub getFils {
  44. my ($this) = @_;
  45. return $this->{FILS};
  46. }
  47. sub getLock {
  48. my ($this) = @_;
  49. return $this->{LOCK};
  50. }
  51. 1;
  52. ####################### FIN PACKAGES ###########################
  53. ####################### MAIN ###########################
  54. my $pere;
  55. my $fils;
  56. my $LEVEL=0;
  57. $pere = undef;
  58. $fils = "4,5";
  59. my $proc1 = new Job( "1", "alias1", $pere, $fils, "0", "unknown", "0" );
  60. $pere = undef;
  61. $fils = "6";
  62. my $proc2 = new Job( "2", "alias2", $pere, $fils, "0", "unknown", "0" );
  63. $pere = undef;
  64. $fils = "8,9";
  65. my $proc3 = new Job( "3", "alias3", $pere, $fils, "0", "unknown", "0" );
  66. $pere = "1";
  67. $fils = "7";
  68. my $proc4 = new Job( "4", "alias4", $pere, $fils, "0", "unknown", "0" );
  69. $pere = "1";
  70. $fils = "7";
  71. my $proc5 = new Job( "5", "alias5", $pere, $fils, "0", "unknown", "0" );
  72. $pere = "2";
  73. $fils = "8";
  74. my $proc6 = new Job( "6", "alias6", $pere, $fils, "0", "unknown", "0" );
  75. $pere = "4,5";
  76. $fils = "8";
  77. my $proc7 = new Job( "7", "alias7", $pere, $fils, "0", "unknown", "0" );
  78. $pere = "7,5,6,3";
  79. $fils = undef;
  80. my $proc8 = new Job( "8", "alias8", $pere, $fils,, "0", "unknown", "0" );
  81. $pere = "3";
  82. $fils = undef;
  83. my $proc9 = new Job( "9", "alias9", $pere, $fils, "0", "unknown", "0" );
  84. print "listJob : @listJob\n";
  85. print Data::Dumper::Dumper @tabProc;
  86.  foreach my $row (@tabProc)
  87. {
  88.  if ($row->{PERE} eq undef)
  89.  {
  90.   $row->{PERE} = "NULL";
  91.  }else
  92.  {
  93.   $row->{PERE} =~ s/,/ /g;
  94.  }
  95.  if ($row->{FILS} eq undef)
  96.  {
  97.   $row->{FILS} = "NULL";
  98.  }
  99.  else
  100.  {
  101.   $row->{FILS} =~ s/,/ /g;
  102.  }
  103.  if ($row->{PERE} eq "NULL" )
  104.  {
  105.   $row->{TYPE} = "PERE-0";
  106.  }
  107.  else
  108.  {
  109.   if ($row->{FILS} eq "NULL" )
  110.   {
  111.    $row->{TYPE} = "FILS";
  112.   }
  113.   else
  114.   {
  115.    $row->{TYPE} = "PERE";
  116.   }
  117.   $row->{STARTED} = 0;
  118.  }
  119.  $LEVEL+=1;
  120. }
  121. print Data::Dumper::Dumper @tabProc;
  122. print "LEVEL : $LEVEL\n";
  123. my $RETOUR;
  124. my @tabProc_temp=@tabProc;
  125. my @tabProcFini=();
  126. my $i=0;
  127. while( @tabProc_temp )
  128. {
  129. $i=0;
  130.  foreach my $row (@tabProc_temp)
  131.  {
  132.   if ($row->{LOCK} == 0)
  133.   {
  134.    $RETOUR = "Not OK";
  135.    print "PROCESS $row->{ID_PROCESS} lets work on it! \n";
  136.    if ($RETOUR eq "OK" )
  137.    {
  138.     print "PROCESS","$row->{ID_PROCESS} is Running \n";
  139.     push(@tabProcFini,$row->{ID_PROCESS});
  140.     @tabProc_temp = @tabProc_temp[0..($i-1),($i+1)..$#tabProc_temp];
  141.     print "\n";
  142.    }
  143.    else
  144.    {
  145.     print "PROCESS ","$row->{ID_PROCESS} is Stopped \n";
  146.     if ($row->{TYPE} eq "PERE-0" )
  147.     {
  148.      sleep rand 5;
  149.      print "PROCESS ","$row->{ID_PROCESS} well started \n\n";
  150.      push(@tabProcFini,$row->{ID_PROCESS});
  151.      @tabProc_temp = @tabProc_temp[0..($i-1),($i+1)..$#tabProc_temp];
  152.     }else
  153.     {
  154.      my @tab1 = split(/ /,$row->{PERE});
  155.      my $tailletab1 = scalar @tab1;
  156.      my @tab2=@tabProcFini;
  157.      my %hash = map{$_ => 1} (@tab1, @tab2);
  158.      my @tab = keys %hash;
  159.      my $nombre_elements_commun = @tab1 + @tab2 - @tab;
  160.      if($nombre_elements_commun == $tailletab1)
  161.      {
  162.       print "PROCESS ","$row->{ID_PROCESS} Parents: $row->{PERE} \n";
  163.       print "PROCESS ","$row->{ID_PROCESS} Les elements de la liste \"PERE\" du process $row->{ID_PROCESS} sont tous présents dans le tableau \@tabProcFini \n";
  164.       sleep rand 5;
  165.       print "PROCESS ","$row->{ID_PROCESS} well started \n\n";
  166.       push(@tabProcFini,$row->{ID_PROCESS});
  167.       @tabProc_temp = @tabProc_temp[0..($i-1),($i+1)..$#tabProc_temp];
  168.      }else
  169.      {
  170.       print "PROCESS ","$row->{ID_PROCESS} Les elements de la liste \"PERE\" du process $row->{ID_PROCESS} NE sont PAS tous présents dans le tableau \@tabProcFini \n";
  171.       print "PROCESS ","$row->{ID_PROCESS} Let's try another process \n\n";
  172.      }
  173.     }
  174.     $RETOUR = "OK";
  175.     if ($RETOUR ne "OK" )
  176.     {
  177.      print "PROCESS","$row->{ID_PROCESS} not started \n";
  178.      exit(1);
  179.     }
  180.    }
  181.   }
  182.   else
  183.   {
  184.    print "$row->{ID_PROCESS} Locked !!! \n";
  185.    push(@tabProcFini,$row->{ID_PROCESS});
  186.    @tabProc_temp = @tabProc_temp[0..($i-1),($i+1)..$#tabProc_temp];
  187.    print "\n";
  188.   }
  189.  $i++;
  190.  #print "tabProc_temp : @tabProc_temp\n";
  191.  print "tabProcFini : @tabProcFini\n\n";
  192.  }
  193. }


 
Toutes les propositions sont les bienvenue, je sèche vraiment  :ange:


Message édité par Super_carotte le 13-12-2011 à 09:46:33
Reply

Marsh Posté le 13-12-2011 à 09:43:40   

Reply

Marsh Posté le 13-12-2011 à 13:24:43    

Vu que dans le modèle standard d'un fork, le processus fils ne partage pas l'environnement mémoire avec son processus père, mais en fait une copie, il n'y a aucune chance que les processus fils accèdent au tableau @tableau1.
 
Une solution à ce problème est décrite ici: http://docstore.mik.ua/orelly/perl [...] h16_13.htm
Bon, c'est pas portable dans tous les environnements, donc pas portable sous windows par exemple.
 

Citation :

J’essaie de mettre en place un multi thread sur le code suivant.

Il y a une raison particulière pour réinventer la roue, plutôt qu'utiliser une solution éprouvée comme Coro?
 
A+,


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 13-12-2011 à 15:51:51    

Bonjour,
 
Tout d'abord, merci pour cette réponse.
 
Ce que j'essaie de faire, c'est de mettre en place un script de démarrage de jobs de façon hiérarchisé.
Donc j'ai créé un code (cf ci-dessus) qui fait cela mais sans parallélisation. Maintenant que ce code fonctionne, j’essaie d'y implanter la parallélisation.
 
Mais étant un débutant en perl, il est fort possible que ma méthode ou que les bibliothèques utilisée ne soient pas les bonnes.
 
Pensez vous que coro puisse gérer un lancement hiérarchisé d'action en parallèle? En quoi est-il different de ForkManager?
En effet, dans sa description j'ai pu lire:  

Citation :

They are similar to kernel threads but don't (in general) run in parallel at the same time even on SMP machines


Du coup, cela ne signifie t'il pas que la parallélisation ne fonctionne pas sur coro?
 
Merci,
Benjamin

Reply

Marsh Posté le 13-12-2011 à 16:17:35    

Comme dit dans une doc, "Coro implements cooperative multitasking/multithreading with explicit task switching, while threads implements scheduled multitasking/multithreading. The advantage of Coro is that you don't get any race conditions. The advantage of threads is that you can get true parallelism across more than one CPU."
 
Mais si vous avez besoins de threads, pourquoi ne pas avoir utilisé ce qui existait déjà dans perl?
Bon en tout cas, si vous êtes sur une architecture de type unix, votre approche par des fork, plus l'utilisation de mêmoire partagée devrait suffire. Si vous êtes sous Win32, vaut mieux pas penser à cette approche, vu déjà que fork y est émulé par perl. Il doit y avoir moyen de faire ce que vous voulez, mais de manière OS dépendante avec les modules WIN32.
 
A+,


Message édité par gilou le 13-12-2011 à 16:41:15

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 14-12-2011 à 10:01:40    

Bonjour,
Mon code doit être multi-platefrome car il doit tourner sur des UNIX et des Win32.  
Donc pas de fork car ça doit pouvoir tourner sur du win32 et pas d'utilisation de "modules WIN32" car ça doit tourner sur de Unix.
 
Il me reste quelle option ?  :??:

Reply

Marsh Posté le 14-12-2011 à 11:49:24    

De partir sur Coro et de laisser tomber le vrai parallélisme (ou de rester avec fork, mais de pas compter dessus sur une plateforme WIN32, ou de toute façon, IPC::Shareable n'a pas l'air d'être supporté), ou éventuellement essayer d'utiliser les threads Perl (mais comme j'ai jamais eu l'occasion de les utiliser dans mes programmes, je en sais s'ils implémentent un vrai parallélisme sous WIN32).
La le problème est pas limité à Perl: a moins de passer par des librairies spécialisées et multiplateformes ajoutant le support du vrai parallélisme la ou il est utile, le problème est assez général à tout code devant fonctionner sur des OS différents.
Il reste aussi la possibilité d'écrire du code OS dépendant avec un test sur l'architecture ($^O) pour décider de ce qui est appelé (un équivalent des ifdef du C) et en ce cas, la lecture de ceci: http://www.perlmonks.org/bare/?node_id=331029 n'est pas inutile pour la partie mémoire partagée et fork sous Windows (le bug est peut être corrigé depuis)
A+,


Message édité par gilou le 14-12-2011 à 13:27:37

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 16-12-2011 à 09:15:49    

Re bonjour,  :hello:  
 
Après en avoir parlé avec les collègues, il s’avère que le code ne sera démarré que depuis des Red Hat.
En fait, la Red Hat va se contenter de lancer des ordres de façon parallélisé aux différents serveurs (unix, linux et win32).
 
Donc il me semble que al solution forkManager reste viable. (tant mieux, coro ne m'a pas semblé evidant a utilisé et je n'ai pas trouvé beaucoup d'exemples sur son utilisation).
 
Merci de m'avoir donné ton avis,  ;)  
 
Cordialement,
Benjamin.

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed