1 | use std::future::Future; |
2 | use std::panic::catch_unwind; |
3 | use std::thread; |
4 | |
5 | use async_executor::{Executor, Task}; |
6 | use async_io::block_on; |
7 | use async_lock::OnceCell; |
8 | use futures_lite::future; |
9 | |
10 | /// Spawns a task onto the global executor (single-threaded by default). |
11 | /// |
12 | /// There is a global executor that gets lazily initialized on first use. It is included in this |
13 | /// library for convenience when writing unit tests and small programs, but it is otherwise |
14 | /// more advisable to create your own [`Executor`]. |
15 | /// |
16 | /// By default, the global executor is run by a single background thread, but you can also |
17 | /// configure the number of threads by setting the `SMOL_THREADS` environment variable. |
18 | /// |
19 | /// Since the executor is kept around forever, `drop` is not called for tasks when the program |
20 | /// exits. |
21 | /// |
22 | /// # Examples |
23 | /// |
24 | /// ``` |
25 | /// let task = smol::spawn(async { |
26 | /// 1 + 2 |
27 | /// }); |
28 | /// |
29 | /// smol::block_on(async { |
30 | /// assert_eq!(task.await, 3); |
31 | /// }); |
32 | /// ``` |
33 | pub fn spawn<T: Send + 'static>(future: impl Future<Output = T> + Send + 'static) -> Task<T> { |
34 | static GLOBAL: OnceCell<Executor<'_>> = OnceCell::new(); |
35 | |
36 | fn global() -> &'static Executor<'static> { |
37 | GLOBAL.get_or_init_blocking(|| { |
38 | let num_threads = { |
39 | // Parse SMOL_THREADS or default to 1. |
40 | std::env::var("SMOL_THREADS" ) |
41 | .ok() |
42 | .and_then(|s| s.parse().ok()) |
43 | .unwrap_or(1) |
44 | }; |
45 | |
46 | for n in 1..=num_threads { |
47 | thread::Builder::new() |
48 | .name(format!("smol- {}" , n)) |
49 | .spawn(|| loop { |
50 | catch_unwind(|| block_on(global().run(future::pending::<()>()))).ok(); |
51 | }) |
52 | .expect("cannot spawn executor thread" ); |
53 | } |
54 | |
55 | // Prevent spawning another thread by running the process driver on this thread. |
56 | let ex = Executor::new(); |
57 | #[cfg (not(target_os = "espidf" ))] |
58 | ex.spawn(async_process::driver()).detach(); |
59 | ex |
60 | }) |
61 | } |
62 | |
63 | global().spawn(future) |
64 | } |
65 | |