Skip to main content

Runtime

The library runs on the Tokio asynchronous runtime: a pool of worker threads that runs every client channel and server and calls your callbacks. You create one Runtime and share it across them.

Lifetime​

Create a Runtime before any communication can take place. It's a shared resource, typically created just after initializing logging and shut down last when exiting.

Rust users can share the runtime with other libraries that also use Tokio. The bindings don't support sharing a runtime.

Examples​

#[tokio::main(flavor = "multi_thread")]
async fn main() -> Result<(), Box<dyn Error>> {
// do things within the context of the runtime
// it is automatically shut down when this async fn returns
Ok(())
}

Set the number of runtime threads to 0 to default to the number of system cores. This provides a safe default that will lead to good multi-core utilization.

Callbacks​

The runtime's thread pool invokes callbacks from the library to user code. Blocking during a callback removes an entire thread from task execution. If all threads in a thread pool are blocked, no communication sessions execute until a thread unblocks.

For example, when you receive a log message via a callback, a synchronous call to write the message to a file will block a thread. If this frequently occurs on all your pool threads, it can cause poor throughput or even task starvation.

Avoid blocking in callbacks. Defer blocking calls to dedicated worker threads, such as a user-managed thread that writes log messages to file.

If you have a case where some blocking is unavoidable, set the number of worker threads to a multiple of the number of system cores, such as 2x or 3x.

note

Binding methods that wait for the runtime to complete an operation, such as creating a TCP or TLS server or changing a server's decode level, can't be called from within a callback. They fail with the RUNTIME_CANNOT_BLOCK_WITHIN_ASYNC parameter error.

Shutdown​

Shutting down the runtime is typically one of the last operations your program should perform before exiting. The call to shutdown is synchronous. When it completes you are assured there are no longer any tasks running and all of the Tokio worker threads have been joined.

warning

A blocked worker thread can cause shutdown to deadlock. For example, if a communication channel makes a callback to user code that permanently blocks, shutdown will cause a deadlock.

If you cannot ensure a clean shutdown, use Runtime.set_shutdown_timeout(..) to set an upper time limit on shutdown. Call this method immediately after creating the Runtime.

Shutting down with a timeout can leak memory, because worker threads that haven't stopped when the timeout occurs are left running. Only use this method if you are exiting the process anyway.

Shutdown examples​

Runtime shutdown is implicit in Rust when tokio::main returns.