asynchronousrustfuturesingle-threaded

Manage blocking functions in signle threaded Rust


I am creating an application and I will maintain an asynchronism system similar to that of Node. So a single thread with a Local Async Executor (I do not use Tokio).

Basically I rely on this article on local async executors.

The problem I encounter is when I see myself using blocking functions.

For example, I would like to use the blocking function read_to_string of the nanomsg sockets (but it is just an example).

If I run it I obviously block the main thread and therefore the application. I could run it in a separate thread, but then I lose the advantage of working with a single thread (need to have Arc or other multithread sync to share data).

Isn't there a simple way to turn any blocking function into a Future that returns the value once executed, without blocking the main thread but without worrying about having to directly manage a secondary thread and have 'send' data structures?


Solution

  • Isn't there a simple way to turn any blocking function into a Future that returns the value once executed, without blocking the main thread but without worrying about having to directly manage a secondary thread and have 'send' data structures?

    It sounds like you want to have your cake and eat it too. You want to have threads without having to ensure your program is thread-safe; you want features provided by Tokio (spawn_blocking) without using Tokio.

    To put it bluntly: you can either code with threads, or without threads. If you code with threads, you have to code in a thread-safe way. If you want to give values to another thread or return values from it, the types of those values must be Send. If you want to return a value to the main thread, which can run other async stuff in the meantime, you need a thread-safe way to signal the main thread that the data is ready. There is no way around any of this.

    If the task you want to run on the thread doesn't need to share any data with the rest of the program (that is, it takes its input by value and returns its output by value) then you don't need Arc directly -- though you still need a way to signal the main thread that the task is done.

    Having said all of that, if your goal is to "do async" but without multi-threading until you absolutely need it (e.g. to run blocking things) then just use Tokio in single-threaded mode. You can still use spawn_blocking in this mode, and as long as you don't create new Tokio tasks through e.g. tokio::spawn then your futures still won't need to be Send.