21 releases

0.2.0-alpha.1 Aug 8, 2019
0.1.18 Feb 4, 2020
0.1.17 Dec 4, 2019
0.1.16 Sep 30, 2019
0.1.2 Mar 30, 2018

#59 in #worker-thread

Download history 35604/week @ 2024-07-20 35286/week @ 2024-07-27 32396/week @ 2024-08-03 33509/week @ 2024-08-10 27162/week @ 2024-08-17 28543/week @ 2024-08-24 27470/week @ 2024-08-31 29696/week @ 2024-09-07 25857/week @ 2024-09-14 24603/week @ 2024-09-21 38015/week @ 2024-09-28 34692/week @ 2024-10-05 36920/week @ 2024-10-12 32713/week @ 2024-10-19 33180/week @ 2024-10-26 27932/week @ 2024-11-02

135,247 downloads per month
Used in fewer than 18 crates

MIT license

570KB
10K SLoC

Tokio Thread Pool

A library for scheduling execution of futures concurrently across a pool of threads.

License

This project is licensed under the MIT license.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in Tokio by you, shall be licensed as MIT, without any additional terms or conditions.


lib.rs:

A work-stealing based thread pool for executing futures.

The Tokio thread pool supports scheduling futures and processing them on multiple CPU cores. It is optimized for the primary Tokio use case of many independent tasks with limited computation and with most tasks waiting on I/O. Usually, users will not create a ThreadPool instance directly, but will use one via a runtime.

The ThreadPool structure manages two sets of threads:

  • Worker threads.
  • Backup threads.

Worker threads are used to schedule futures using a work-stealing strategy. Backup threads, on the other hand, are intended only to support the blocking API. Threads will transition between the two sets.

The advantage of the work-stealing strategy is minimal cross-thread coordination. The thread pool attempts to make as much progress as possible without communicating across threads.

Worker overview

Each worker has two queues: a deque and a mpsc channel. The deque is the primary queue for tasks that are scheduled to run on the worker thread. Tasks can only be pushed onto the deque by the worker, but other workers may "steal" from that deque. The mpsc channel is used to submit futures while external to the pool.

As long as the thread pool has not been shutdown, a worker will run in a loop. Each loop, it consumes all tasks on its mpsc channel and pushes it onto the deque. It then pops tasks off of the deque and executes them.

If a worker has no work, i.e., both queues are empty. It attempts to steal. To do this, it randomly scans other workers' deques and tries to pop a task. If it finds no work to steal, the thread goes to sleep.

When the worker detects that the pool has been shut down, it exits the loop, cleans up its state, and shuts the thread down.

Thread pool initialization

Note, users normally will use the threadpool created by a runtime.

By default, no threads are spawned on creation. Instead, when new futures are spawned, the pool first checks if there are enough active worker threads. If not, a new worker thread is spawned.

Spawning futures

The spawning behavior depends on whether a future was spawned from within a worker or thread or if it was spawned from an external handle.

When spawning a future while external to the thread pool, the current strategy is to randomly pick a worker to submit the task to. The task is then pushed onto that worker's mpsc channel.

When spawning a future while on a worker thread, the task is pushed onto the back of the current worker's deque.

Blocking annotation strategy

The blocking function is used to annotate a section of code that performs a blocking operation, either by issuing a blocking syscall or performing any long running CPU-bound computation.

The strategy for handling blocking closures is to hand off the worker to a new thread. This implies handing off the deque and mpsc. Once this is done, the new thread continues to process the work queue and the original thread is able to block. Once it finishes processing the blocking future, the thread has no additional work and is inserted into the backup pool. This makes it available to other workers that encounter a blocking call.

Dependencies

~1.5MB
~25K SLoC