Pipe en entrée et en sortie. Blocage.
Bonjour,
Je fais suite au fil Pipe en entrée et en sortie.
Il s'avère que le script utilisé fonctionne bien pour les entrées courtes, mais il y a un blocage dès que l'entrée devient volumineuse. Le code suivant permet de mettre en relief le problème.
Code:
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
|
use strict;
use warnings;
use File::Slurp;
use IPC::Open2;
#* Paramètres. *
my $nomsource = "source.php";
sub filtrecommande {
my ($commande, $entree) = @_;
#* Ouverture des descripteurs de fichiers. *
my ($df_sortie, $df_entree);
my $pid = open2($df_sortie, $df_entree, $commande);
#* Envoie des données en entrée du filtre. *
print $df_entree $entree;
close $df_entree;
print STDERR "Balise 1.\n";
waitpid($pid, 0);
print STDERR "Balise 2.\n";
#* Récupération des données en sortie de filtre. *
my $sortie;
while ( my $ligne = <$df_sortie> ) {
$sortie .= $ligne;
}
close $df_sortie;
#* Terminaison. *
return $sortie;
}
my $source = read_file($nomsource, binmode => ':utf8');
my $produit = filtrecommande('php', $source);
print STDERR "Produit : <<$produit>>\n"; |
Le script s'arrête, lorsque 'source.php' est volumineux, entre la balise 1 et la balise 2. Manifestement le fils (qui lance le programme 'php' je pense) ne termine pas. Mon analyse est que le tampon de sortie du programme 'php' est plein.
Est-ce que quelqu'un aurait des idées, et pourrait me conseiller sur un mode de résolution ?
Eléments de réponse. 25/01/2015#0
Le script suivant fonctionne.
Code:
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
|
use strict;
use warnings;
use File::Slurp;
use IPC::Open2;
#* Paramètres. *
my $nomsource = "source1.php";
sub filtrecommande {
my ($commande, $entree) = @_;
#* Ouverture des descripteurs de fichiers. *
my ($df_sortie, $df_entree);
my $pid = open2($df_sortie, $df_entree, $commande);
#* Envoie des données en entrée du filtre. *
print $df_entree $entree;
close $df_entree;
#* Récupération des données en sortie de filtre. *
my $sortie;
while ( my $ligne = <$df_sortie> ) {
$sortie .= $ligne;
}
close $df_sortie;
#* Attente processus fils. *
waitpid($pid, 0);
#* Terminaison. *
return $sortie;
}
my $source = read_file($nomsource, binmode => ':utf8');
my $produit = filtrecommande('php', $source);
print STDERR "Produit : <<$produit>>\n"; |
Eléments de réponse. 25/01/2015#1
En réponse à une des questions de Lolo78 dans son message du 14 janvier :
- un ficher en entrée ('source1.php') d'une taille de 15 604 octets passe ;
- un fichier en entrée ('source2.php') d'une taille de 85 194 octets ne passe pas.
Eléments de réponse. 25/01/2015#2
En réponse à une des questions de Lolo78 dans son message du 14 janvier, la commande suivante fonctionne.
Eléments de réponse. 25/01/2015#3
Autre éléments de réponse au message de Lilo78 en date du 14 janvier.
Citation:
- Ton code PHP, est-ce qu'il ne fait que lire séquentiellement le contenu qui lui est passé et renvoyer le contenu transformé? Est-ce qu'il charge tout le contenu en entrée en mémoire?
Le code PHP que je mets en entrée ne lit en fait rien. Il manipule quelques variables simples.
La question qu'on pourrait en revanche se poser, c'est la manière dont se comporte l'intépréteur PHP. Et là, pour l'heure, je n'en sais rien. Je suppose néanmoins qu'il doit charger tout le fichier texte, effectuer une précompilation en mémoire, et exécuter le bytecode obtenu (et resté en mémoire).
Citation:
- Ton code PHP fonctionne sur un serveur? Lequel? Le code est-il multi-threadé? N'y a-t-il pas un risque d'interblocage dans ce cas?
Je ne fonctionne pas du tout sur une architecture client - serveur. Je me contente d'utiliser l'interpréteur PHP en local, comme un préprocesseur de texte, comme on a l'habitude de le faire avec M4.
Citation:
Sinon, une ou deux pistes un peu différentes: le module PHP du CPAN et le module interpréteur PHP du CPAN. Ces deux modules paraissent les plus prometteurs, puisqu'ils semblent être en mesure d'exécuter du PHP deluis l'interpréteur Perl, mais il y a quelques autres modules relatifs à PHP sur le CPAN, fais une recherche "CPAN PHP" sur Google ou autre, tu trouveras peut-être une solution te convenant.
Cette idée me plaît bien. Je vais creuser.
Eléments de réponse. 25/01/2015#4
Citation:
Envoyé par
Philou67430
Je crois l'avoir déjà dit, mais l'usage du pipe en entrée et en sortie avec IPC::Open2 nécessite que les deux processus en communication (c'est nécessaire mais pas forcément suffisant) fassent leurs écritures en direct, sans bufferisation. Ça signifie pour perl d'avoir au moins l'instruction $|++ en tête de programme. Néanmoins, je vois que tu fermes le filehandle une fois écris ce que tu as à envoyer au processus fils, donc cela devrait "flusher" la sortie... mais dans ce type d'architecture, je mettrais ceinture et bretelle, c'est trop sensible.
Ca ne marche pas. Le code suivant bloque toujours.
Code:
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
|
use strict;
use warnings;
use File::Slurp;
use IPC::Open2;
#* Paramètres. *
my $nomsource = "source1.php";
$|++;
sub filtrecommande {
my ($commande, $entree) = @_;
#* Ouverture des descripteurs de fichiers. *
my ($df_sortie, $df_entree);
my $pid = open2($df_sortie, $df_entree, $commande);
#* Envoie des données en entrée du filtre. *
print $df_entree $entree;
close $df_entree;
print STDERR "Balise 1.\n";
waitpid($pid, 0);
print STDERR "Balise 2.\n";
#* Récupération des données en sortie de filtre. *
my $sortie;
while ( my $ligne = <$df_sortie> ) {
$sortie .= $ligne;
}
close $df_sortie;
#* Terminaison. *
return $sortie;
}
my $source = read_file($nomsource, binmode => ':utf8');
my $produit = filtrecommande('php', $source);
print STDERR "Produit : <<$produit>>\n"; |