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}