Skip to main content

tokio/task/
spawn.rs

1use crate::runtime::BOX_FUTURE_THRESHOLD;
2use crate::task::JoinHandle;
3use crate::util::trace::SpawnMeta;
4
5use std::future::Future;
6
7cfg_rt! {
8    /// Spawns a new asynchronous task, returning a
9    /// [`JoinHandle`] for it.
10    ///
11    /// The provided future will start running in the background immediately
12    /// when `spawn` is called, even if you don't await the returned
13    /// [`JoinHandle`].
14    ///
15    /// Spawning a task enables the task to execute concurrently to other tasks. The
16    /// spawned task may execute on the current thread, or it may be sent to a
17    /// different thread to be executed. The specifics depend on the current
18    /// [`Runtime`](crate::runtime::Runtime) configuration. In a
19    /// [running runtime][running-runtime], the task will start immediately in the
20    /// background. On a blocked runtime, the user must drive the runtime forward (for
21    /// example, by calling [`Runtime::block_on`](crate::runtime::Runtime::block_on)).
22    ///
23    /// It is guaranteed that spawn will not synchronously poll the task being spawned.
24    /// This means that calling spawn while holding a lock does not pose a risk of
25    /// deadlocking with the spawned task.
26    ///
27    /// There is no guarantee that a spawned task will execute to completion.
28    /// When a runtime is shutdown, all outstanding tasks are dropped,
29    /// regardless of the lifecycle of that task.
30    ///
31    /// This function must be called from the context of a Tokio runtime. Tasks running on
32    /// the Tokio runtime are always inside its context, but you can also enter the context
33    /// using the [`Runtime::enter`](crate::runtime::Runtime::enter()) method.
34    ///
35    /// [running-runtime]: ../runtime/index.html#driving-the-runtime
36    ///
37    /// # Examples
38    ///
39    /// In this example, a server is started and `spawn` is used to start a new task
40    /// that processes each received connection.
41    ///
42    /// ```no_run
43    /// # #[cfg(not(target_family = "wasm"))]
44    /// # {
45    /// use tokio::net::{TcpListener, TcpStream};
46    ///
47    /// use std::io;
48    ///
49    /// async fn process(socket: TcpStream) {
50    ///     // ...
51    /// # drop(socket);
52    /// }
53    ///
54    /// #[tokio::main]
55    /// async fn main() -> io::Result<()> {
56    ///     let listener = TcpListener::bind("127.0.0.1:8080").await?;
57    ///
58    ///     loop {
59    ///         let (socket, _) = listener.accept().await?;
60    ///
61    ///         tokio::spawn(async move {
62    ///             // Process each socket concurrently.
63    ///             process(socket).await
64    ///         });
65    ///     }
66    /// }
67    /// # }
68    /// ```
69    ///
70    /// To run multiple tasks in parallel and receive their results, join
71    /// handles can be stored in a vector.
72    /// ```
73    /// # #[tokio::main(flavor = "current_thread")] async fn main() {
74    /// async fn my_background_op(id: i32) -> String {
75    ///     let s = format!("Starting background task {}.", id);
76    ///     println!("{}", s);
77    ///     s
78    /// }
79    ///
80    /// let ops = vec![1, 2, 3];
81    /// let mut tasks = Vec::with_capacity(ops.len());
82    /// for op in ops {
83    ///     // This call will make them start running in the background
84    ///     // immediately.
85    ///     tasks.push(tokio::spawn(my_background_op(op)));
86    /// }
87    ///
88    /// let mut outputs = Vec::with_capacity(tasks.len());
89    /// for task in tasks {
90    ///     outputs.push(task.await.unwrap());
91    /// }
92    /// println!("{:?}", outputs);
93    /// # }
94    /// ```
95    /// This example pushes the tasks to `outputs` in the order they were
96    /// started in. If you do not care about the ordering of the outputs, then
97    /// you can also use a [`JoinSet`].
98    ///
99    /// [`JoinSet`]: struct@crate::task::JoinSet
100    ///
101    /// # Panics
102    ///
103    /// Panics if called from **outside** of the Tokio runtime.
104    ///
105    /// # Using `!Send` values from a task
106    ///
107    /// The task supplied to `spawn` must implement `Send`. However, it is
108    /// possible to **use** `!Send` values from the task as long as they only
109    /// exist between calls to `.await`.
110    ///
111    /// For example, this will work:
112    ///
113    /// ```
114    /// use tokio::task;
115    ///
116    /// use std::rc::Rc;
117    ///
118    /// fn use_rc(rc: Rc<()>) {
119    ///     // Do stuff w/ rc
120    /// # drop(rc);
121    /// }
122    ///
123    /// # #[tokio::main(flavor = "current_thread")]
124    /// # async fn main() {
125    /// tokio::spawn(async {
126    ///     // Force the `Rc` to stay in a scope with no `.await`
127    ///     {
128    ///         let rc = Rc::new(());
129    ///         use_rc(rc.clone());
130    ///     }
131    ///
132    ///     task::yield_now().await;
133    /// }).await.unwrap();
134    /// # }
135    /// ```
136    ///
137    /// This will **not** work:
138    ///
139    /// ```compile_fail
140    /// use tokio::task;
141    ///
142    /// use std::rc::Rc;
143    ///
144    /// fn use_rc(rc: Rc<()>) {
145    ///     // Do stuff w/ rc
146    /// # drop(rc);
147    /// }
148    ///
149    /// #[tokio::main]
150    /// async fn main() {
151    ///     tokio::spawn(async {
152    ///         let rc = Rc::new(());
153    ///
154    ///         task::yield_now().await;
155    ///
156    ///         use_rc(rc.clone());
157    ///     }).await.unwrap();
158    /// }
159    /// ```
160    ///
161    /// Holding on to a `!Send` value across calls to `.await` will result in
162    /// an unfriendly compile error message similar to:
163    ///
164    /// ```text
165    /// `[... some type ...]` cannot be sent between threads safely
166    /// ```
167    ///
168    /// or:
169    ///
170    /// ```text
171    /// error[E0391]: cycle detected when processing `main`
172    /// ```
173    #[track_caller]
174    pub fn spawn<F>(future: F) -> JoinHandle<F::Output>
175    where
176        F: Future + Send + 'static,
177        F::Output: Send + 'static,
178    {
179        let fut_size = std::mem::size_of::<F>();
180        if fut_size > BOX_FUTURE_THRESHOLD {
181            spawn_inner(Box::pin(future), SpawnMeta::new_unnamed(fut_size))
182        } else {
183            spawn_inner(future, SpawnMeta::new_unnamed(fut_size))
184        }
185    }
186
187    #[track_caller]
188    pub(super) fn spawn_inner<T>(future: T, meta: SpawnMeta<'_>) -> JoinHandle<T::Output>
189    where
190        T: Future + Send + 'static,
191        T::Output: Send + 'static,
192    {
193        use crate::runtime::{context, task};
194
195        #[cfg(all(
196            tokio_unstable,
197            feature = "taskdump",
198            feature = "rt",
199            target_os = "linux",
200            any(
201                target_arch = "aarch64",
202                target_arch = "x86",
203                target_arch = "x86_64"
204            )
205        ))]
206        let future = task::trace::Trace::root(future);
207        let id = task::Id::next();
208        let task = crate::util::trace::task(future, "task", meta, id.as_u64());
209
210        match context::with_current(|handle| handle.spawn(task, id, meta.spawned_at)) {
211            Ok(join_handle) => join_handle,
212            Err(e) => panic!("{}", e),
213        }
214    }
215}