2010-09-22 14 views
2

J'ai un programme qui appelle un autre programme et le traitement de la sortie de l'enfant, à savoir:Comment effectuer une lecture non bloquante à partir d'un tube en Perl?

my $pid = open($handle, "$commandPath $options |"); 

Maintenant, j'ai essayé quelques différentes façons de lire de la poignée sans bloquer avec peu ou pas de succès.

Je trouve des questions connexes:

Mais ils souffrent de problèmes:

  • ioctl se bloque régulièrement perl
  • sysread blocs sur 0 octets (une occurrence fréquente)

Je ne sais pas comment résoudre ce problème.

+0

Est-ce Windows? – mob

+0

Voir [cette réponse] (http://stackoverflow.com/questions/1530592/why-does-my-perl-sysread-block-when-reading-from-a-socket/1532251#1532251) - utilisez 'select() 'pour déterminer s'il y a des données disponibles à lire. – Ether

+0

@Ether sélection ne fonctionne pas sur les handles de fichiers sur les fenêtres – tzenes

Répondre

4

Les tuyaux ne sont pas aussi fonctionnels sur Windows que sur les systèmes Unix-y. Vous ne pouvez pas utiliser le select à 4 arguments et la capacité par défaut est minuscule.

Il est préférable d'essayer une solution de contournement basée sur un socket ou un fichier.

$pid = fork(); 
if (defined($pid) && $pid == 0) { 
    exit system("$commandPath $options > $someTemporaryFile"); 
} 
open($handle, "<$someTemporaryFile"); 

Maintenant, vous avez deux ou trois autres boîtes de vers à traiter - en cours d'exécution waitpid périodiquement pour vérifier si le processus d'arrière-plan a cessé de créer la sortie, appelant seek $handle,0,1 pour effacer la condition EOF après avoir lu de $handle, nettoyage le fichier temporaire, mais cela fonctionne.

J'ai écrit le module Forks::Super pour faire face à des problèmes comme celui-ci (et beaucoup d'autres). Pour ce problème, vous l'utiliseriez comme

use Forks::Super; 
my $pid = fork { cmd => "$commandPath $options", child_fh => "out" }; 
my $job = Forks::Super::Job::get($pid); 
while (!$job->is_complete) { 
    @someInputToProcess = $job->read_stdout(); 
    ... process input ... 
    ... optional sleep here so you don't consume CPU waiting for input ... 
} 
waitpid $pid, 0; 
@theLastInputToProcess = $job->read_stdout(); 
+0

@mobrule ma compréhension est que je ne peux pas utiliser select sur un handle de fichier, donc cela ne fait que recréer le même problème que j'ai actuellement. – tzenes

+0

Vous n'avez pas besoin d'utiliser select sur un descripteur de fichier. La lecture sur un descripteur épuisé retournera 'undef' sans bloquer, et vous pourrez alors appeler' seek HANDLE, 0,1' pour effacer la condition eof et en relire la lecture. – mob

+0

@mob devrais-je alors chercher à quelle distance j'avais déjà lu? Ou est-ce que cela le gère? – tzenes