2010-07-12 17 views
2

J'utilise la gemme open4 et j'ai des problèmes de lecture depuis les processus engendrés stdout. J'ai un programme de rubis, test1.rb:Pourquoi ne peut-on pas ouvrir read4 à partir de stdout lorsque le programme attend stdin?

print 'hi.' # 3 characters 
$stdin.read(1) # block 

Et un autre programme rubis dans le même répertoire, test2.rb:

require 'open4' 

pid, stdin, stdout, stderr = Open4.popen4 'ruby test1.rb' 
p stdout.read(2) # 2 characters 

Quand je lance le deuxième programme:

$ ruby test2.rb 

Il se trouve juste là pour toujours sans rien imprimer. Pourquoi cela arrive-t-il, et que puis-je faire pour l'arrêter?

Répondre

2

je devais changer test1.rb à ce sujet. Je ne sais pas pourquoi.

print 'hi.' # 3 characters 
$stdout.flush 
$stdin.read(1) # block 
1

Je ne suis pas un expert en processus. De ma première vue du document API, la séquence d'utilisation de open4 est la suivante: envoie d'abord du texte à stdin, puis ferme stdin et enfin lit le texte de stdout.

Donc. Vous pouvez le test2.rb comme celui-ci

require 'open4' 

pid, stdin, stdout, stderr = Open4.popen4 'ruby test1.rb' 
stdin.puts "something" # This line is important 
stdin.close # It might be optional, open4 might close itself. 
p stdout.read(2) # 2 characters 
2

Par défaut, tout ce que vous print à stdout ou à un autre fichier est écrit dans une mémoire tampon de Ruby (ou la bibliothèque standard C, qui est sous Ruby). Le contenu du tampon est transmis au système d'exploitation si l'un des événements suivants se produit:

  • Le tampon est plein.
  • Vous fermez stdout.
  • Vous avez imprimé une séquence de nouvelle ligne («\ n»)
  • Vous appelez le flush explicitement.

Pour les autres fichiers, un flush est également fait à d'autres occasions, comme ftell.

Si vous mettez stdout en mode unbuffered ($stdout.sync = true), le tampon ne sera pas utilisé.

stderr n'est pas tamponné par défaut. La raison de la mise en mémoire tampon est l'efficacité: l'agrégation des données de sortie dans un tampon peut sauver de nombreux appels système (appels au système d'exploitation). Les appels système sont très expensive: Ils prennent plusieurs centaines ou même des milliers de cycles CPU. En les évitant avec un peu de code et quelques tampons dans l'espace utilisateur, on obtient une bonne accélération.

Une bonne lecture sur le tampon: Why does printf not flush after the call unless a newline is in the format string?