IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Perl Discussion :

fork : créer UN fifo entre le père et SES fils


Sujet :

Langage Perl

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Inscrit en
    Août 2007
    Messages
    39
    Détails du profil
    Informations forums :
    Inscription : Août 2007
    Messages : 39
    Par défaut fork : créer UN fifo entre le père et SES fils
    Bonjour

    Je cherche à mettre en parallèle le téléchargement simultané de pages web avec analyse en direct et je me retrouve confronté à un problème de communication entre processus.

    En gros j'ai une liste de N sites à visiter, pour ce je fais M forks consécutifs (N > M), et je souhaite passer la liste des sites dans un fifo, et chacun des fils viendrait ensuite piocher dans le fifo. Lorsqu'un fils a terminé, il viendrait lire une nouvelle adresse dans le fifo, si le fifo est vide, alors le fils meurt.

    J'ai tenté le code suivant mais le souci est que seul l'ainé des fils vient lire dans le fifo, les autres fils meurent aussitôt.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
     
    #!/usr/bin/perl -w
     
    use strict ;
    use warnings ;
     
    my $nb_fork = '3' ; # Nombre de fois que le script sera dupliqué => nbre de connections simultanées
     
    my $pid = '-1' ;
    my $i = '0' ;
    my @liste = ('eins', 'zwei', 'drei', 'vier', 'funf', 'sechs', 'sieben', 'acht', 'neun', 'zehn') ;
     
     
    pipe (EN, SO) ; # appel à pipe ou tube nommé : même résultat
     
    while ($pid != '0' and $i < $nb_fork)
    {	$pid = fork ;
    	$i++ ;
    }
     
    if ($pid == '0')	# L'un des processus fils
    {	$i-- ;
     
    	close (SO) ;
    	open (ENTREE, "<&EN") ; # J'ai tenté de dupliqué le descripteur de fichier mais sans changement
     
    	print "Ici on est dans le fils et \$i vaut $i\n" ;
    	while (my $var = <ENTREE>)
    	{	print "Le fils n°$i s'occupe de $var" ;
    		sleep (1) ;
    	} 
    	print "  --> Sortie du fils n°$i\n" ;
    	close ENTREE ;
    	close EN ;
    }
    else			# Le processus père
    {	close EN ;
    	open (SORTIE, ">&SO") ;
    	foreach my $site (@liste)
    	{	print SORTIE "$site\n" ;
    	}
    	print "   --> Le père attend la fin des fils\n" ;
    	close SORTIE ;
    	close SO ;
    	do {} while (wait () >= '0') ;
    	print "   --> Sortie du père\n" ;
    }
    produit la sortie suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
    Ici on est dans le fils et $i vaut 0
    Ici on est dans le fils et $i vaut 1
    Ici on est dans le fils et $i vaut 2
       --> Le père attend la fin des fils
    Le fils n°0 s'occupe de eins
      --> Sortie du fils n°1
      --> Sortie du fils n°2
    Le fils n°0 s'occupe de zwei
    Le fils n°0 s'occupe de drei
    Le fils n°0 s'occupe de vier
    Le fils n°0 s'occupe de funf
    Le fils n°0 s'occupe de sechs
    Le fils n°0 s'occupe de sieben
    Le fils n°0 s'occupe de acht
    Le fils n°0 s'occupe de neun
    Le fils n°0 s'occupe de zehn
      --> Sortie du fils n°0
       --> Sortie du père
    On voit bien que le cadet et le benjamin quittent aussitôt car semblent incapables de lire dans le tube, seul l'ainé effectue le travail.

    J'ai tenté avec et sans duplication des descripteurs de fichiers tant en entrée qu'en sortie, tant avec pipe qu'avec un tube nommé.

    Quelqu'un saurait-il me dire comment faire en sorte que plusieurs fils viennent lire dans un même tube ??? D'après les infos que j'ai trouvé, c'est possible mais rien qui ne dise comment ...

    Merci d'avance
    Yann

  2. #2
    Expert confirmé
    Avatar de Jedai
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2003
    Messages
    6 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Avril 2003
    Messages : 6 245
    Par défaut
    Pourquoi ne pas inverser le modèle ? Tu crées un pipe par fils, le père utilise IO::Select ou IO::Poll pour les surveiller, un fils informe son père lorsqu'il a terminé son boulot (et lui transmet ses résultat éventuellement) et attend que son père lui renvoie du boulot.
    Tu pourrais également utiliser Thread::Queue, si tu as un Perl récent, les threads sont devenus presque utilisables.
    As-tu également envisagé d'utiliser LWP::Parallel ?
    Si tu es un peu familier avec l'architecture de POE (ce qui est une bonne idée de toute façon), il y a un composant pour http.

    --
    Jedaï

  3. #3
    Membre averti
    Inscrit en
    Août 2007
    Messages
    39
    Détails du profil
    Informations forums :
    Inscription : Août 2007
    Messages : 39
    Par défaut
    Citation Envoyé par Jedai Voir le message
    Pourquoi ne pas inverser le modèle ? Tu crées un pipe par fils, le père utilise IO::Select ou IO:oll pour les surveiller, un fils informe son père lorsqu'il a terminé son boulot (et lui transmet ses résultat éventuellement) et attend que son père lui renvoie du boulot.
    Oui pourquoi pas ... A vrai dire j'avais réussi à simuler un fifo (un entrée un sortie) entre un père et ses threads fils, avec des tableaux partagés (les fils shift'ent le tableau de lecture et push'ent celui d'écriture), mais là avec fork pas moyen de partager des variables ... Et je cherchais une solution similaire du genre le père reste totalement passif en attendant la fin de ses fils ... je vais tout de même tenter ça ... Vu que j'aurais certainement besoin de faire communiquer les fils avec leur père ...

    Citation Envoyé par Jedai Voir le message
    Tu pourrais également utiliser Thread::Queue, si tu as un Perl récent, les threads sont devenus presque utilisables.
    Debian unstable, donc difficile d'avoir un perl plus récent ...

    Citation Envoyé par Jedai Voir le message
    As-tu également envisagé d'utiliser LWP:arallel ?
    Si tu es un peu familier avec l'architecture de POE (ce qui est une bonne idée de toute façon), il y a un composant pour http.
    Non je vais devoir m'en passer, car j'ai besoin d'analyser en temps réel chaque page que je télécharge afin de recueillir d'autres URL mais surtout déterminer en fonction du contenu des pages si celles-ci ont été modifiées, et donc déterminer si elles doivent être mises à jour ou non ... ça me permettra de réduire la quantité de données à télécharger, donc de réduire la durée du script, et donc de le passer plus souvent ...



    J'essaye IO::Select et IO:oll pour voir et je te tiens au jus ...

  4. #4
    Membre averti
    Inscrit en
    Août 2007
    Messages
    39
    Détails du profil
    Informations forums :
    Inscription : Août 2007
    Messages : 39
    Par défaut
    Ok, j'ai réussi à faire communiquer dans le sens des fils vers le père, maintenant ça coince du père vers les fils :s

    voici le code (la partie utile du moins) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
     
    #!/usr/bin/perl -w
     
    use strict ;
    use warnings ;
     
    use IO::Pipe ;
    use IO::Select ;
     
    my $nb_fork = '3' ;			# Nombre de fois que le script sera dupliqué => nbre de connections simultanées
    my %donnees_contacts ;			# Hachage de hachage contenant les informations des contacts (date de dernière maj, nb d'articles et de comms)
     
    ################################################################################
     
    my @liste = ('eins', 'zwei', 'drei', 'vier', 'funf', 'sechs', 'sieben', 'acht', 'neun', 'zehn') ;
     
    print "  <-- @liste -->\n" ;
     
    ################################################################################
     
    my $pid = '-1' ;
    my $i = '0' ;
    my @tabPipesPereFils ;	# Communication du père vers ses fils
    my @tabPipesFilsPere ;	# Communication des fils vers leur père
     
    # Clonage du prog
    for ($i = '0' ; $i < $nb_fork and $pid != '0' ; $i++)
    {	push @tabPipesPereFils, new IO::Pipe;
    	push @tabPipesFilsPere, new IO::Pipe;
    	$pid = fork () ;
    }
     
    ################################################################################
     
    if (defined ($pid) and $pid > '0')	# Processus père
    {	print "On est entré dans le cas du père\n" ;
     
    	my $s = IO::Select->new();
     
    	# Mise en lecture/écriture des tubes et création de la liste d'écoute
    	for ($i = 0 ; $i < $nb_fork ; $i++)
    	{	$tabPipesPereFils[$i]->writer () ;
    		$tabPipesFilsPere[$i]->reader () ;
    		$s->add ($tabPipesFilsPere[$i]) ;
    	}
     
    	print "P : Attente de demande des fils\n" ;
    	while (wait () >= '0' and my @ready = $s->can_read ())		# On attend soit la fin des fils, soit l'arrivée de données
    	{	foreach my $fils (@ready)
    		{	my $ligne = <$fils> ;
    			next unless (defined $ligne) ;		
     
    			print "P reçoit ==> $ligne" if (defined ($ligne)) ;
     
    			if ($ligne =~ /(\d+) : \+{3}/)
    			{	my $f = $1 ;
    				my $adresse = shift @liste ;
    				print {$tabPipesPereFils[$f]} "$adresse\n" ;
    				print "P reçoit => Ecriture de $adresse dans le tube n°$f\n" ;
    			}
    		}
    	}
     
    	print "Tous les fils ont fini, on sort du père\n" ;
    }
    elsif (defined ($pid))			# Processus fils
    {	$i-- ;
    	$tabPipesPereFils[$i]->reader () ;
    	$tabPipesFilsPere[$i]->writer () ;
     
    	my $entree = $tabPipesPereFils[$i] ;
     
    #	my $s = IO::Select->new();
    #	$s->add ($tabPipesPereFils[$i]) ;
     
    	print "On est dans le fils n°$i\n" ;
     
    	# Le fils demande du boulot à son père
    	print {$tabPipesFilsPere[$i]} "$i : +++\n" ;
     
    #	my @ready = $s->can_read () ;
    	{	
    #		my $ready = shift @ready ;
     
    		my $adresse  = <$tabPipesPereFils[$i]> ;
    		die unless (defined ($adresse)) ;		# On quitte si rien n'a pu être lu
    		print "F$i reçoit : $adresse\n" ;
     
    		# Informe le père que le fils a fini son travail et le père lui renvoie une nouvelle tache
    		print {$tabPipesFilsPere[$i]} "$i : +++\n" ; 
    	}
    }
    ce qui me produit ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
      <-- eins zwei drei vier funf sechs sieben acht neun zehn -->
    On est dans le fils n°0
    F0 reçoit : IO::Pipe::End=GLOB(0x7571d0)
    On est dans le fils n°1
    F1 reçoit : IO::Pipe::End=GLOB(0x757050)
    On est dans le fils n°2
    F2 reçoit : IO::Pipe::End=GLOB(0x76ff00)
    On est entré dans le cas du père
    P : Attente de demande des fils
    P reçoit ==> 0 : +++
    P reçoit => Ecriture de eins dans le tube n°0
    P reçoit ==> 1 : +++
    P reçoit => Ecriture de zwei dans le tube n°1
    P reçoit ==> 2 : +++
    P reçoit => Ecriture de drei dans le tube n°2
    P reçoit ==> 0 : +++
    P reçoit => Ecriture de vier dans le tube n°0
    P reçoit ==> 1 : +++
    P reçoit => Ecriture de funf dans le tube n°1
    P reçoit ==> 2 : +++
    P reçoit => Ecriture de sechs dans le tube n°2
    Tous les fils ont fini, on sort du père
    Pour une raison que j'ignore, le fils est incapable de lire les données en provenance du père ... J'ai tenté de reproduire le même schéma que dans le père avec IO::Select, mais j'obtiens un bloquage qui ne semble pas avoir d'explication valable

    Je sais que pour écrire dans un tube référencé par un tableau, il faut utiliser un bloc {}, j'ai tenté de reproduire la même chose en entrée à savoir :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    print {$tabPipesPereFils[$i]} "ligne à écrire" ; # Depuis le père
     
    $ligne = <{$tabPipesFilsPere[$i]}> ; # Depuis le fils
    mais rien n'y fait

    Si quelqu'un à une idée du problème, elles sont les bienvenues, moi je sêche ...

    Merci d'avance ...

Discussions similaires

  1. [XSLT 2.0] Ignorer un père et ses fils
    Par henri93 dans le forum XSL/XSLT/XPATH
    Réponses: 2
    Dernier message: 12/09/2012, 14h55
  2. causer entre un père et un fils
    Par dva2tlse dans le forum Débuter
    Réponses: 13
    Dernier message: 18/12/2008, 20h38
  3. communication entre le pere et ses fils
    Par facilus68 dans le forum Réseau
    Réponses: 2
    Dernier message: 13/12/2006, 23h02
  4. Réponses: 8
    Dernier message: 09/11/2006, 14h01
  5. Réponses: 2
    Dernier message: 03/02/2004, 21h56

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo