Ich mache eine kleine Ncurses-Anwendung in Rust, die mit einem Kindprozess kommunizieren muss. Ich habe bereits einen Prototyp in Common Lisp geschrieben; Das gif here wird hoffentlich zeigen, was ich machen möchte. Ich versuche es neu zu schreiben, weil CL eine große Menge an Speicher für ein so kleines Werkzeug benötigt.Wie lese ich die Ausgabe eines Child-Prozesses ohne Blockierung in Rust?
Ich habe Rust nicht vorher (oder andere Low-Level-Sprachen) verwendet, und ich habe einige Schwierigkeiten herauszufinden, wie man mit dem Unterprozess interagieren.
Was ich derzeit tun, ist in etwa so:
den Prozess erstellen:
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; }, };
Pass es zu einer unendlichen (bis User-Exits) Schleife, die Eingabe liest und Griffe und wartet auf eine Ausgabe wie diese (und schreibt sie auf den Bildschirm):
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, }; }
Der Aufruf an read_to_string
blockiert jedoch das Programm, bis der Prozess beendet wird. Von dem, was ich sehen kann read_to_end
und read
scheinen auch zu blockieren. Wenn ich versuche, etwas wie ls
auszuführen, das sofort beendet wird, funktioniert es, aber mit etwas, das nicht wie python
oder sbcl
beendet wird, fährt es nur fort, sobald ich den Unterprozess manuell beende.
Edit:
Basierend auf this answer, änderte ich den Code BufReader
zu verwenden:
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,
}
}
jedoch das Problem immer noch gleich bleibt. Es liest alle verfügbaren Zeilen und blockiert dann. Da das Werkzeug mit jedem Programm arbeiten soll, gibt es keine Möglichkeit zu erraten, wann die Ausgabe enden wird, bevor versucht wird zu lesen. Es scheint auch keine Möglichkeit zu geben, ein Timeout für BufReader
zu setzen.
Danke für die hilfreiche Erklärung. Ich werde in MIO schauen, und wenn das nicht klappt, werde ich separate Threads verwenden. – jkiiski