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}