Robię małą aplikację ncurses w Rust, która musi komunikować się z procesem podrzędnym. Mam już prototyp napisany w Common Lisp; GIF here ma nadzieję, że pokażę, co chcę zrobić. Próbuję przepisać to, ponieważ CL używa ogromnej ilości pamięci dla tak małego narzędzia.Jak odczytać dane wyjściowe procesu potomnego bez blokowania w Rust?
Nie użyłem Rusta przed (lub innymi niskopoziomowymi językami) i mam problem z ustaleniem sposobu interakcji z pod-procesem.
Co mam obecnie robi to mniej więcej w ten sposób:
Tworzenie procesu:
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; }, };
przekazać go do nieskończonej (do użytkownika) wyjść pętli, która odczytuje i obsługuje wejście i słucha takich wyników (i zapisuje je na ekranie):
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, }; }
Jednak wywołanie read_to_string
blokuje program do momentu zakończenia procesu. Z tego, co widzę, read_to_end
i read
również wydaje się blokować. Jeśli spróbuję uruchomić coś w rodzaju ls
, które od razu się kończy, działa, ale z czymś, co nie kończy się tak jak python
lub sbcl
, działa ono tylko po ręcznym zabiciu podprocesu.
Edit:
podstawie this answer, zmieniłem kod do korzystania BufReader
:
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,
}
}
Jednak problem nadal pozostaje taka sama. Będzie czytać wszystkie linie, które są dostępne, a następnie blokować. Ponieważ narzędzie ma współpracować z dowolnym programem, nie ma możliwości odgadnięcia, kiedy wyjście się zakończy, przed próbą odczytu. Wydaje się, że nie ma sposobu na ustawienie limitu czasu dla BufReader
.
Dzięki za pomocne wyjaśnienie. Zajrzę do MIO, a jeśli to nie zadziała, użyję osobnych wątków. – jkiiski