4 releases

0.2.1 Apr 10, 2021
0.2.0 Mar 28, 2021
0.1.1 Nov 21, 2020
0.1.0 Nov 3, 2020
Download history 72/week @ 2021-01-15 46/week @ 2021-01-22 136/week @ 2021-01-29 58/week @ 2021-02-05 117/week @ 2021-02-12 67/week @ 2021-02-19 73/week @ 2021-02-26 180/week @ 2021-03-05 53/week @ 2021-03-12 120/week @ 2021-03-19 124/week @ 2021-03-26 71/week @ 2021-04-02 246/week @ 2021-04-09 72/week @ 2021-04-16 82/week @ 2021-04-23 100/week @ 2021-04-30

419 downloads per month
Used in 4 crates (2 directly)

MIT OR Apache-2.0 OR Zlib

55KB
883 lines

switchyard

GitHub Workflow Status Crates.io Documentation License

Real-time compute-focused async executor with job pools, thread-local data, and priorities.

Example

use switchyard::Switchyard;
use switchyard::threads::{thread_info, single_pool_one_to_one};
// Create a new switchyard with one job pool and empty thread local data
let yard = Switchyard::new(1, single_pool_one_to_one(thread_info(), Some("thread-name")), ||()).unwrap();

// Spawn a task on pool 0 and priority 10 and get a JoinHandle
let handle = yard.spawn(0, 10, async move { 5 + 5 });
// Spawn a lower priority task on the same pool
let handle2 = yard.spawn(0, 0, async move { 2 + 2 });

// Wait on the results
assert_eq!(handle.await + handle2.await, 14);

How Switchyard is Different

Switchyard is different from other existing async executors, focusing on situations where precise control of threads and execution order is needed. One such situation is using task parallelism to parallelize a compute workload.

Priorites

Each task has a priority and tasks are ran in order from high priority to low priority.

// Spawn task with lowest priority.
yard.spawn(0, 0, async move { /* ... */ });
// Spawn task with higher priority. If both tasks are waiting, this one will run first.
yard.spawn(0, 10, async move { /* ... */ });

Job Pools

Inside each yard there can be multiple (up to [MAX_POOLS]) different "job pools". Each thread in the pool is dedicated to a single pool. By having multiple pools, it can help prevent executor exhaustion.

// Create a yard with two job pools. Each logical core gets two threads, one per pool.
let yard = Switchyard::new(2, double_pool_two_to_one(thread_info(), Some("thread-name")), ||()).unwrap();

// Spawn task on pool 0.
yard.spawn(0, 0, async move { /* ... */ });
// Spawn task on pool 1.
yard.spawn(1, 0, async move { /* ... */ });

Thread Local Data

Each yard has some thread local data that can be accessed using spawn_local. Both the thread local data and the future generated by the async function passed to spawn_local may be !Send and !Sync. The future will only be resumed on the thread that created it.

If the data is Send, then you can call access_per_thread_data to get a vector of mutable references to all thread's data. See it's documentation for more information.

// Create yard with thread local data. The data is !Sync.
let yard = Switchyard::new(1, single_pool_one_to_one(thread_info(), Some("thread-name")), || Cell::new(42)).unwrap();

// Spawn task that uses thread local data. Each running thread will get their own copy.
yard.spawn_local(0, 0, |data| async move { data.set(10) });

MSRV

1.51

Future MSRV bumps will be breaking changes.

License: MIT OR Apache-2.0 OR Zlib

Dependencies

~2MB
~34K SLoC