Best practice for constraining an `async` block to a single thread when using Tokio?
Hey 🦀s,
Is there a best practice for forcing an async block to be run on a single system thread? (C.f. this old GitHub thread.)
I'm using CUDA from Rust, and every new thread I create has to be registered with CUDA. Thus I want to run async blocks that look like this:
async move {
register_thread();
// Do CUDA stuff
}
Thoughts:
- Naively running this with
tokio::spawndoesn't work becausetokiomight move my block between system threads at any yield point inside my block. LocalSetdoesn't work (for me) because it's notSendand thus my control code can't usetokio::spawn. There's a workaround described in the docs but I think it's too complicated.block_in_placedoesn't work (I think) because to run async code you need to callHandle::current().block_onwhich will hand theasyncblock to the the originaltokioruntime which may move it between system threads (IIUC).
So, my final solution is to just create a new single-threaded runtime inside a new system thread, like this:
std::thread::spawn({
move || {
tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap()
.block_on(async move {
register_thread();
// Do CUDA stuff
});
}
});
Obviously this feels inelegant - I don't think I should be creating multiple tokio runtimes.
Anyone know the correct way to do this?
EDIT: I ended up using this solution:
tokio::task::spawn_blocking({
move || {
tokio::runtime::Handle::current().block_on(async move {
register_thread();
// Do CUDA stuff
})
}
});