W.r.t. the sempiternal probem of "I have a spawned async piece of work (a task), but with a potentially-blocking synchronous piece of code in it; how do I handle it?"
- Note: let's assume a non-
current_threadexecutor.
As of now, this has 2/2.5 answers: - Straight-forward: wrap the blocking piece of code in
spawn_blocking(), should it be'static + Send(minor overhead);- When the latter is not true, you can also use
block_in_place()(higher overhead);
- When the latter is not true, you can also use
- Spawn your "task" as a blocking one (
spawn_blocking(), or using your own thread-pool or whatnot), and then useblock_on()around theasyncpart(s) in it.
But it turns out there may be a third option, based on the observation that a block_on() thread is not a core/worker_thread, and thus, a block_on() thread need not abide by async-coöperation rules.
- See the following thread over the Rust Community Discord: https://discord.com/channels/273534239310479360/1480019037831565324
Hence:
- spawn a
block_on()thread: - spawn some separate thread, either through
spawn_blocking(), or using your own thread-pool or whatnot. - call
Handle::block_on()in it - Run your
async"task" in it, inlined, - with the sync-blocking code inlined in it as well.
/// Could also be named `spawn_uncooperative()`.
fn spawn_maybe_blocking<R: Send>(
handle: &Handle,
task_that_blocks_inside: impl Send + Future<Output = R>,
) -> JoinHandle<R>
{
handle.clone().spawn_blocking(move || {
handle.block_on(task_that_blocks_inside)
})
}
```Usage:```rs
spawn_maybe_blocking(Handle::current(), async move {
while let Some(item) = stream.next().await {
do_blocking_work(item);
}
}).await