bridging async and sync rust

连接 Rust 异步和同步代码

Posted by pinylin on March 12, 2023
refer: [Bridging Async and Sync Rust Code - A lesson learned while working with Tokio Greptime](https://greptime.com/blogs/2023-03-09-bridging-async-and-sync-rust)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
impl Sequencer for PlainSequencer {
    fn generate(&self) -> Vec<i32> {
        let bound = self.bound;
        futures::executor::block_on(async move {
            RUNTIME.spawn(async move {
                let mut res = vec![];
                for i in 0..bound {
                    res.push(i);
                    tokio::time::sleep(Duration::from_millis(100)).await;
                }
                res
            }).await.unwrap()
        })
    }
}

Best practice

Based on the above analysis and Rust’s generator-based cooperative asynchronous characteristics, we can summarize some tips when bridging asynchronous and synchronous code in Rust:

  • Combining asynchronous code with synchronous code that can cause blocking is never a wise choice.
  • When calling asynchronous code from a synchronous context, use futures::executor::block_on and spawn the async code to a dedicated runtime, because the former will block the current thread.
  • On the other hand, if you have to call blocking synchronous code from an asynchronous context, it is recommended to use tokio::task::spawn_blocking to execute the code on a dedicated executor that handles blocking operations.