How to wrap a blocking operation into a future?

#1

I’m trying to understanding the underlying mechanism of Future.

Suppose I have an blocking operation: e.g., fetching data packet from socket with read function, which originally blocks when no data is available.

//just a casually written example.
fn fetch_data(s:&mut socket)->&[u8]{
    s.read()
}

If I want to wrap it into a future, is it true that I have to spawn a thread to watch this blocking operation?

I have read the similar discussion on stackoverflow. The answer to which is using a thread.

So is this the best answer that we can do, given that the system does not offer corresponding non-blocking method.

If coroutine, which is based on Futures can avoid the using of system thread, then why spawning a thread is involved when trying to wrap a blocking operation into Future? Or actually I was wrong, there IS a better solution?

Thanks.

#2

For futures to work, usage of the Future has to be non-blocking (i.e. it has to quickly return NotReady, instead of waiting and blocking the thread that polls it). This way one thread can poll any number of Futures, instead of being stuck waiting on one of them.

When you have an operation that blocks the thread that invokes it, that thread is completely taken over by the blocking task, and can’t be used for any other non-blocking async operations at the same time. Therefore, you have to spawn another thread in order to “sacrifice it” for the thread-blocking operation.


As for how to do it, the easiest solution is to create a CpuPool with futures-cpupool and spawn blocking operations there.

1 Like
#3

You can use tokio_threadpool::blocking to run the blocking operation in the current thread. The current thread will hand over its pending tasks to another thread, making sure that no other work is actually blocked by your blocking operation.

1 Like