Ho avuto un certo successo nel risolvere questo mio problema. Ecco i dettagli, con alcune spiegazioni, nel caso qualcuno che abbia un problema simile trovi questa pagina. Ma se non ti interessa i dettagli, , ecco la risposta breve:
Utilizzare PTY.uova nel modo seguente (con il proprio comando del corso):
require 'pty'
cmd = "blender -b mball.blend -o //renders/ -F JPEG -x 1 -f 1"
begin
PTY.spawn(cmd) do |stdout, stdin, pid|
begin
# Do stuff with the output here. Just printing to show it works
stdout.each { |line| print line }
rescue Errno::EIO
puts "Errno:EIO error, but this probably just means " +
"that the process has finished giving output"
end
end
rescue PTY::ChildExited
puts "The child process exited!"
end
E ecco la risposta lunga, con troppi dettagli:
Il vero problema sembra essere che se un processo doesn sciacquare esplicitamente il suo stdout, quindi tutto ciò che viene scritto su stdout viene memorizzato sul buffer piuttosto che effettivamente inviato, fino a quando il processo non viene eseguito, in modo da minimizzare l'IO (questo è apparentemente un dettaglio di implementazione di molte librerie C, realizzato in modo tale che il throughput sia massimizzato tramite IO meno frequente). Se è possibile modificare facilmente il processo in modo che stia scaricando regolarmente stdout, questa sarebbe la soluzione. Nel mio caso, era un frullatore, quindi un po 'intimidatorio per un noob completo come me per modificare la fonte.
Ma quando si eseguono questi processi dalla shell, visualizzano lo stdout nella shell in tempo reale e lo stdout non sembra essere memorizzato nel buffer. È bufferizzato solo quando viene chiamato da un altro processo, ma se viene gestita una shell, lo stdout viene visto in tempo reale, senza buffer.
Questo comportamento può anche essere osservato con un processo ruby come processo secondario il cui output deve essere raccolto in tempo reale. Basta creare uno script, random.rb, con la seguente riga:
Poi uno script Ruby per chiamarlo e restituisce la sua uscita:
IO.popen("ruby random.rb") do |random|
random.each { |line| puts line }
end
Vedrai che non si ottiene il risultato in tempo reale come ci si potrebbe aspettare, ma tutto in una volta dopo. STDOUT è in fase di buffering, anche se si esegue random.rb da soli, non viene memorizzato nel buffer. Questo può essere risolto aggiungendo un'istruzione STDOUT.flush
all'interno del blocco in random.rb. Ma se non puoi cambiare la fonte, devi aggirare questo. Non puoi svuotarlo dall'esterno del processo.
Se il sottoprocesso può stampare in shell in tempo reale, deve esserci un modo per catturarlo con Ruby anche in tempo reale. E c'è. Devi usare il modulo PTY, incluso nel ruby core, credo (1.8.6 comunque). La cosa triste è che non è documentato. Ma ho trovato alcuni esempi di utilizzo per fortuna.
Innanzitutto, per spiegare cos'è PTY, corrisponde a pseudo terminal. Fondamentalmente, consente allo script ruby di presentarsi al sottoprocesso come se fosse un utente reale che ha appena digitato il comando in una shell. Quindi qualsiasi comportamento alterato che si verifica solo quando un utente ha avviato il processo attraverso una shell (come lo STDOUT non viene bufferizzato, in questo caso) si verificherà. Nascondendo il fatto che un altro processo ha avviato questo processo consente di raccogliere lo STDOUT in tempo reale, poiché non viene memorizzato nel buffer.
per fare questo lavoro con lo script random.rb come il bambino, provare il seguente codice:
require 'pty'
begin
PTY.spawn("ruby random.rb") do |stdout, stdin, pid|
begin
stdout.each { |line| print line }
rescue Errno::EIO
end
end
rescue PTY::ChildExited
puts "The child process exited!"
end
+1 - Bello e ben fatto! :) –
Questa è una buona risposta. Ha reso la mia giornata. –
Questo è ottimo, ma credo che i parametri del blocco stdin e stdout dovrebbero essere scambiati. Vedi: http://www.ruby-doc.org/stdlib-1.9.3/libdoc/pty/rdoc/PTY.html#method-c-spawn –