Suppose a loop on main like this:
use crate::modules::very_ext::{one, two};
use crate::modules::much_wow::logic;
let result;
loop {
let foo = one.next().await.expect("boom");
// Do something with foo
result = logic(foo)
}
This far, great. What happens when the logic inside the loop needs to "react" to multiple external events?
If we do something like this:
use crate::modules::very_ext::{one, two};
use crate::modules::much_wow::logic;
let result;
loop {
let foo = one.next().await.expect("boom");
let bar = two.next().await.expect("boom");
// Do something with foo
result = logic(foo, bar)
}
then logic
will only run after:
foo
resolves firstbar
eventually resolves as well(which is not what we want, we need to react whenever a new value for
either foo
or bar
is externally ready to be passed to the main
loop).
By reading tokio
's docs, my guess is that this can be solved by using threads and channels. But I'm confused on exactly how. I am thinking it like this:
mpsc
channel.one
and two
into their own threads.mpsc
channel.Am I overthinking this? Is there a simpler way (assume the general problem with multiple producers, not just two)?
Thank you!
You can spawn lightweight tasks out of both futures, which will allow you to await them both without serializing them. It is conceptually similar to the solution you proposed, but doesn't use additional threads (it runs foo
and bar
on the normal executor threads, interleaving them with other futures as they await), and the channels created are one-shot channels highly optimized for this purpose.
loop {
// spawn foo and bar to run in the background
let foo = tokio::spawn(one.next());
let bar = tokio::spawn(two.next());
// awaiting foo now also executes bar
let foo = foo.await.unwrap().expect("boom");
let bar = bar.await.unwrap().expect("boom");
result = logic(foo, bar);
}