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