Skip to main content

unblock

Function unblock 

Source
pub fn unblock<T>(work: impl FnOnce() -> T + Send + 'static) -> BlockingWork<T> ⓘ
where T: Send + 'static,
Expand description

Runs work on a thread of a pool kept for blocking work, and returns a future of its result.

Use it for work that blocks, such as a file read, a host-name lookup or a call into a library with no async form. If such work runs on the thread that polls tasks, it holds up every other task on that thread. Here it holds up only the pool thread that runs it. The task that awaits the future is woken when the work is done.

The work is submitted to the pool before unblock returns, not when the future is first polled. An idle pool thread takes it. If none is idle, a new thread is started, up to a limit of 500 threads. Beyond that, the work waits in a queue, in submission order, until a thread is free.

Pool threads are named zruntime blocking work. A thread is reused for later work. It exits after ten seconds with nothing to run, so an unused pool holds no threads.

Work that never ends holds its thread forever. If every pool thread is held that way, later work waits forever too. The pool suits work that ends on its own. For work that waits on other pool work, or that runs as long as the program does, use std::thread::spawn instead.

The work runs to the end whether or not the future is polled, and even if the future is dropped. Dropping the future gives up the wait for the result. It cannot cancel the work, or remove it from the queue before it starts. Nothing waits for the pool threads, so work that is still running or queued when the process exits is lost.

The returned future needs no runtime. It wakes the waker from its most recent poll, so it can be awaited under any executor, from a task on any thread.

§Panics

If work panics, the panic is caught on the pool thread, which carries on with other work. The poll that would have returned the value raises the panic again, with its original payload. A future that is dropped before that poll never sees the panic. The panic hook runs once, when the panic happens, and not again when the panic is raised again.

unblock itself panics if the pool has no thread and cannot start one for the work, as std::thread::spawn does when it fails. If the pool has threads, the work waits for one of them instead.

§Example

A sleep stands in for blocking work. The example drives the future with block_on from the futures crate, but the block_on of any executor works, as unblock needs no runtime:

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

use futures::executor::block_on;
use zruntime::unblock;

let answer = unblock(|| {
    thread::sleep(Duration::from_millis(10));
    42
});

assert_eq!(block_on(answer), 42);

§WASI

Not available on WASI. Blocking work needs a thread of its own to run on, out of the way of the thread that polls tasks, and wasm32-wasip1 and wasm32-wasip2 cannot start a thread. Running the work on the thread that polls its future instead would block that thread, and every task on it, until the work is done, which is no async at all.

This can change once a WASI target with threads can be told apart from one without: wasm32-wasip1-threads can start threads, but no cfg sets it apart from wasm32-wasip1.