uexec/
lib.rs

1//! uexec - simple work-stealing global and local executor
2//!
3//! The global executor is lazily spawned on first use.
4//! It doesn't spawn any worker threads by default but you can use
5//! [spawn_workers] to do that.
6//!
7//! # Examples
8//!
9//! ```
10//! # use futures_lite::future;
11//! // spawn several worker threads
12//! uexec::spawn_workers(4);
13//!
14//! // spawn a task on the multi-threaded executor
15//! let task1 = uexec::spawn(async {
16//!     1 + 2
17//! });
18//! // spawn a task on the local executor (same thread)
19//! let task2 = uexec::spawn_local(async {
20//!     3 + 4
21//! });
22//! let task = future::zip(task1, task2);
23//!
24//! // run the executor
25//! uexec::block_on(async {
26//!     assert_eq!(task.await, (3, 7));
27//! });
28//!
29//! // terminate our worker threads
30//! uexec::terminate_workers();
31//! ```
32
33#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
34
35#[cfg(doctest)]
36doc_comment::doctest!("../README.md");
37
38mod executor;
39mod future_holder;
40mod global_executor;
41mod handle;
42mod local_future;
43mod main_task;
44mod receiver;
45mod state;
46mod threads;
47mod waker;
48mod workers;
49
50use executor::Executor;
51use global_executor::GlobalExecutor;
52use local_future::LocalFuture;
53use waker::DummyWaker;
54use workers::Workers;
55
56use std::{future::Future, sync::Arc, task::Waker};
57
58use crossbeam_utils::sync::Parker;
59use once_cell::sync::Lazy;
60
61/* Implicit global Executor */
62static EXECUTOR: Lazy<GlobalExecutor> = Lazy::new(Default::default);
63
64/* Internal noop waker */
65static DUMMY_WAKER: Lazy<Waker> = Lazy::new(|| Arc::new(DummyWaker).into());
66
67/* List of wokers we spawned */
68static WORKERS: Lazy<Workers> = Lazy::new(Default::default);
69
70/* Implicit State for futures local to this thread */
71thread_local! {
72    static PARKER: Parker = Parker::new();
73    static LOCAL_EXECUTOR: Executor = Executor::local();
74}
75
76pub use handle::{JoinHandle, LocalJoinHandle};
77
78/// Runs the global and the local executor on the current thread until the given future is Ready
79///
80/// # Examples
81///
82/// ```
83/// let task = uexec::spawn(async {
84///     1 + 2
85/// });
86/// uexec::block_on(async {
87///     assert_eq!(task.await, 3);
88/// });
89/// ```
90pub fn block_on<R: 'static, F: Future<Output = R> + 'static>(future: F) -> R {
91    LOCAL_EXECUTOR.with(|executor| executor.block_on(future))
92}
93
94/// Spawns a task onto the multi-threaded global executor.
95///
96/// # Examples
97///
98/// ```
99/// # use futures_lite::future;
100/// let task1 = uexec::spawn(async {
101///     1 + 2
102/// });
103/// let task2 = uexec::spawn(async {
104///     3 + 4
105/// });
106/// let task = future::zip(task1, task2);
107///
108/// uexec::block_on(async {
109///     assert_eq!(task.await, (3, 7));
110/// });
111/// ```
112pub fn spawn<R: Send + 'static, F: Future<Output = R> + Send + 'static>(
113    future: F,
114) -> JoinHandle<R> {
115    EXECUTOR.spawn(future)
116}
117
118/// Spawns a task onto the local executor.
119///
120/// The task does not need to be `Send` as it will be spawned on the same thread.
121///
122/// # Examples
123///
124/// ```
125/// # use futures_lite::future;
126/// let task1 = uexec::spawn_local(async {
127///     1 + 2
128/// });
129/// let task2 = uexec::spawn_local(async {
130///     3 + 4
131/// });
132/// let task = future::zip(task1, task2);
133///
134/// uexec::block_on(async {
135///     assert_eq!(task.await, (3, 7));
136/// });
137/// ```
138pub fn spawn_local<R: 'static, F: Future<Output = R> + 'static>(future: F) -> LocalJoinHandle<R> {
139    LOCAL_EXECUTOR.with(|executor| executor.spawn(future))
140}
141
142/// Spawn new worker threads
143///
144/// New futures spawned using [spawn] may be executed on several of the spawned workers
145///
146/// # Examples
147/// ```
148/// uexec::spawn_workers(4);
149/// # uexec::terminate_workers();
150/// ```
151pub fn spawn_workers(threads: u8) {
152    WORKERS.spawn(threads);
153}
154
155/// Terminate all worker threads
156///
157/// Pending futures will be dropped
158///
159/// # Examples
160/// ```
161/// # uexec::spawn_workers(4);
162/// uexec::terminate_workers();
163/// ```
164pub fn terminate_workers() {
165    WORKERS.terminate();
166}