pub fn with_thread<T: Send + 'static, TFuture: Future<Output = T> + Send + 'static>(
    original_future: TFuture
) -> Pin<Box<dyn Future<Output = T> + Send + 'static>>
Expand description

Run a future on a separate thread.

Useful when future has a blocking code. Normally such blocking code will also block current all asynchronous tasks. This helper mitigates such issue by running blocking future on a separate thread with its own Tokio runtime.

Examples

use std::{thread, pin::Pin, time::Duration};

use futures::{future, Future};
use cs_utils::futures::{wait, with_thread};
 
#[tokio::main(worker_threads = 1)]
async fn main() {
    // variable to count how many iterations
    // the normal future has run
    static mut RUN_CNT: u64 = 0;

    // create a future that blocks current thread
    let blocking_future = async move {
        thread::sleep(Duration::from_secs(1));    
    };
     
    // create a future that intended to run in background
    let normal_future = async move {
        loop {
            unsafe { RUN_CNT += 1 }
            wait(100).await;
        }
    };
     
    // create futures list
    let futures: Vec<Pin<Box<dyn Future<Output = ()>>>> = vec![
        Box::pin(with_thread(blocking_future)), // <-- wrap the blocking future here
        Box::pin(normal_future),
    ];
     
    // race futures to completion 
    future::select_all(futures).await;
 
    // must go thru multiple iterations in the normal future
    assert!(
        unsafe { RUN_CNT >= 8 } && unsafe { RUN_CNT <= 10 },
        "Normal future must run iterations multiple times.",
    );
}