futurify

Converts sync closures into non-thread blocking futures. Supports futures 0.1 & 0.3

MIT License

Downloads
3K
Stars
3
Committers
1

Futurify

Convert your sync functions into non-blocking thread futures.

Support for both Futures 0.1 and Futures 0.3. By default, Futures 0.3 will be used.

When to use it

This is just an example to illustrate when this library could be useful.

Imagine you're creating an actix-web API and you have and endpoint that has to execute a very long synchronous task.

Normally, most of the modern crates will provide some async variants but still there are some of them that only provide a sync implementation.

This could be problematic as this endpoint could block the main thread and avoid other endpoints from being executed.

Take a look at this code:

use actix_web::{web, App, HttpServer, Responder};
use std::time::Duration;

async fn index_async() -> impl Responder {
    futures::future::ready("Hello world").await
}

async fn index_async_blocking() -> impl Responder {
    futures::future::lazy(|_| {
        std::thread::sleep(Duration::from_secs(5));
        "Hello blocking world"
    })
    .await
}

fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new()
            .route("/", web::get().to_async(index_async))
            .route("/blocking", web::get().to_async(index_async_blocking))
    })
    .workers(1)
    .bind("localhost:8080")?
    .run()
}

If you try to get localhost:8080/blocking and then get localhost:8080, you will be able to see that you won't get any response until the blocking endpoint has returned.

With just a slight change we could get rid of this issue:

async fn index_async_non_blocking() -> impl Responder {
    futurify::wrap(|| {
        std::thread::sleep(Duration::from_secs(5));
        "Hello non blocking world"
    })
}

fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new()
            .route("/", web::get().to(index_async))
            .route("/blocking", web::get().to(index_async_blocking))
            .route("/non-blocking", web::get().to(index_async_non_blocking))
    })
    .workers(1)
    .bind("localhost:8080")?
    .run()
}

Just wrap a closure with futurify::wrap and you'll get a futures 0.3 future ready to be polled.

Futures 0.1 support

If you need support for Futures 0.1 just import the library like this in your Cargo.toml:

futurify = { version = "0.3", features = "futures_01", default-features = false }

That should do the trick!