I have a compute-heavy but interactive (via the sdl2
crate) workload that occasionally performs I/O (file and/or network reads and writes). The results of the I/O operation don't need to be immediately available -- it's possible (and desired) to run the I/O concurrently while the computation is ongoing. On the other hand, I/O is infrequent enough that the vast majority of cases, only one file read/network operation is going on at any given moment in time, if one is going on in the first place. I also return periodically to poll and service SDL window events, making my crate look something like this:
fn main() {
create_sdl2_window();
loop {
check_sdl2_events();
repaint_sdl2_window();
check_io_completion(); // this is where we check if the download is complete
for i in 0..1000000 {
// do something for a finite length of time
if data_from_network_needed {
if !download_complete {
add_to_download_queue("https://users.rust-lang.org/");
// immediately continue computation, allowing the download to progress in the background
} else {
// copy data into internal structures
}
// we can also open files
}
}
}
}
I would like to avoid using async
/.await
; the main reason is that it would require labeling a large number of functions, some of which are performance critical, with async
. I would rather use blocking I/O, but that would unfortunately lead to lag and freezes when the network is slow. The actual computation is highly serial by its nature and cannot be split into multiple threads.
My ideal solution would be to have one thread for computation (let's call this A
) and one for I/O (B
) -- B
would sleep most of the time, only waking when A
requests/sends data. A
would poll B
from time to time using the check_io_completion
function to check whether the I/O's done or not. I'm fine with (and would prefer, due to their simplicity) blocking I/O crates like ureq
or the std::fs::Read
, so long as the operations run on a separate thread.
Do you know of any crates/blog posts/ideas that could help point me in the right direction?