¿Cómo leo la salida de un proceso secundario sin bloquear en Rust?
Estoy haciendo una pequeña aplicación ncurses en Rust que necesita comunicarse con un proceso secundario. Ya tengo un prototipo escrito en Common Lisp; el gifaquí espero que muestre lo que quiero hacer. Estoy tratando de reescribirlo porque CL usa una gran cantidad de memoria para una herramienta tan pequeña.
No he usado Rust antes (u otros lenguajes de bajo nivel), y estoy teniendo problemas para descubrir cómo interactuar con el subproceso.
Lo que estoy haciendo actualmente es más o menos esto:
Crea el proceso:
let mut program = match Command::new(command)
.args(arguments)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn() {
Ok(child) => child,
Err(_) => {
println!("Cannot run program '{}'.", command);
return;
},
};
Pásalo a un bucle infinito (hasta que el usuario salga), que lee y maneja la entrada y escucha la salida como esta (y la escribe en la pantalla):
fn listen_for_output(program: &mut Child,
output_viewer: &TextViewer) {
match program.stdout {
Some(ref mut out) => {
let mut buf_string = String::new();
match out.read_to_string(&mut buf_string) {
Ok(_) => output_viewer.append_string(buf_string),
Err(_) => return,
};
},
None => return,
};
}
La llamada aread_to_string
sin embargo, bloquea el programa hasta que finalice el proceso. Por lo que puedo verread_to_end
yread
También parece bloquear. Si trato de ejecutar algo comols
que sale de inmediato, funciona, pero con algo que no sale comopython
osbcl
solo continúa una vez que elimino el subproceso manualmente.
Editar:
Residencia enesta respuesta, Cambié el código para usarBufReader
:
fn listen_for_output(program: &mut Child,
output_viewer: &TextViewer) {
match program.stdout.as_mut() {
Some(out) => {
let buf_reader = BufReader::new(out);
for line in buf_reader.lines() {
match line {
Ok(l) => {
output_viewer.append_string(l);
},
Err(_) => return,
};
}
},
None => return,
}
}
Sin embargo, el problema sigue siendo el mismo. Leerá todas las líneas disponibles y luego las bloqueará. Como se supone que la herramienta funciona con cualquier programa, no hay forma de adivinar cuándo terminará la salida, antes de intentar leer. No parece haber una manera de establecer un tiempo de espera paraBufReader
ya sea.