• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::task::JoinHandle;
2 
3 cfg_rt_multi_thread! {
4     /// Runs the provided blocking function on the current thread without
5     /// blocking the executor.
6     ///
7     /// In general, issuing a blocking call or performing a lot of compute in a
8     /// future without yielding is problematic, as it may prevent the executor
9     /// from driving other tasks forward. Calling this function informs the
10     /// executor that the currently executing task is about to block the thread,
11     /// so the executor is able to hand off any other tasks it has to a new
12     /// worker thread before that happens. See the [CPU-bound tasks and blocking
13     /// code][blocking] section for more information.
14     ///
15     /// Be aware that although this function avoids starving other independently
16     /// spawned tasks, any other code running concurrently in the same task will
17     /// be suspended during the call to `block_in_place`. This can happen e.g.
18     /// when using the [`join!`] macro. To avoid this issue, use
19     /// [`spawn_blocking`] instead of `block_in_place`.
20     ///
21     /// Note that this function cannot be used within a [`current_thread`] runtime
22     /// because in this case there are no other worker threads to hand off tasks
23     /// to. On the other hand, calling the function outside a runtime is
24     /// allowed. In this case, `block_in_place` just calls the provided closure
25     /// normally.
26     ///
27     /// Code running behind `block_in_place` cannot be cancelled. When you shut
28     /// down the executor, it will wait indefinitely for all blocking operations
29     /// to finish. You can use [`shutdown_timeout`] to stop waiting for them
30     /// after a certain timeout. Be aware that this will still not cancel the
31     /// tasks — they are simply allowed to keep running after the method
32     /// returns.
33     ///
34     /// [blocking]: ../index.html#cpu-bound-tasks-and-blocking-code
35     /// [`spawn_blocking`]: fn@crate::task::spawn_blocking
36     /// [`join!`]: macro@join
37     /// [`thread::spawn`]: fn@std::thread::spawn
38     /// [`shutdown_timeout`]: fn@crate::runtime::Runtime::shutdown_timeout
39     ///
40     /// # Examples
41     ///
42     /// ```
43     /// use tokio::task;
44     ///
45     /// # async fn docs() {
46     /// task::block_in_place(move || {
47     ///     // do some compute-heavy work or call synchronous code
48     /// });
49     /// # }
50     /// ```
51     ///
52     /// Code running inside `block_in_place` may use `block_on` to reenter the
53     /// async context.
54     ///
55     /// ```
56     /// use tokio::task;
57     /// use tokio::runtime::Handle;
58     ///
59     /// # async fn docs() {
60     /// task::block_in_place(move || {
61     ///     Handle::current().block_on(async move {
62     ///         // do something async
63     ///     });
64     /// });
65     /// # }
66     /// ```
67     ///
68     /// # Panics
69     ///
70     /// This function panics if called from a [`current_thread`] runtime.
71     ///
72     /// [`current_thread`]: fn@crate::runtime::Builder::new_current_thread
73     #[track_caller]
74     pub fn block_in_place<F, R>(f: F) -> R
75     where
76         F: FnOnce() -> R,
77     {
78         crate::runtime::scheduler::block_in_place(f)
79     }
80 }
81 
82 cfg_rt! {
83     /// Runs the provided closure on a thread where blocking is acceptable.
84     ///
85     /// In general, issuing a blocking call or performing a lot of compute in a
86     /// future without yielding is problematic, as it may prevent the executor from
87     /// driving other futures forward. This function runs the provided closure on a
88     /// thread dedicated to blocking operations. See the [CPU-bound tasks and
89     /// blocking code][blocking] section for more information.
90     ///
91     /// Tokio will spawn more blocking threads when they are requested through this
92     /// function until the upper limit configured on the [`Builder`] is reached.
93     /// After reaching the upper limit, the tasks are put in a queue.
94     /// The thread limit is very large by default, because `spawn_blocking` is often
95     /// used for various kinds of IO operations that cannot be performed
96     /// asynchronously.  When you run CPU-bound code using `spawn_blocking`, you
97     /// should keep this large upper limit in mind. When running many CPU-bound
98     /// computations, a semaphore or some other synchronization primitive should be
99     /// used to limit the number of computation executed in parallel. Specialized
100     /// CPU-bound executors, such as [rayon], may also be a good fit.
101     ///
102     /// This function is intended for non-async operations that eventually finish on
103     /// their own. If you want to spawn an ordinary thread, you should use
104     /// [`thread::spawn`] instead.
105     ///
106     /// Closures spawned using `spawn_blocking` cannot be cancelled abruptly; there
107     /// is no standard low level API to cause a thread to stop running.  However,
108     /// a useful pattern is to pass some form of "cancellation token" into
109     /// the thread.  This could be an [`AtomicBool`] that the task checks periodically.
110     /// Another approach is to have the thread primarily read or write from a channel,
111     /// and to exit when the channel closes; assuming the other side of the channel is dropped
112     /// when cancellation occurs, this will cause the blocking task thread to exit
113     /// soon after as well.
114     ///
115     /// When you shut down the executor, it will wait indefinitely for all blocking operations to
116     /// finish. You can use [`shutdown_timeout`] to stop waiting for them after a
117     /// certain timeout. Be aware that this will still not cancel the tasks — they
118     /// are simply allowed to keep running after the method returns.  It is possible
119     /// for a blocking task to be cancelled if it has not yet started running, but this
120     /// is not guaranteed.
121     ///
122     /// Note that if you are using the single threaded runtime, this function will
123     /// still spawn additional threads for blocking operations. The current-thread
124     /// scheduler's single thread is only used for asynchronous code.
125     ///
126     /// # Related APIs and patterns for bridging asynchronous and blocking code
127     ///
128     /// In simple cases, it is sufficient to have the closure accept input
129     /// parameters at creation time and return a single value (or struct/tuple, etc.).
130     ///
131     /// For more complex situations in which it is desirable to stream data to or from
132     /// the synchronous context, the [`mpsc channel`] has `blocking_send` and
133     /// `blocking_recv` methods for use in non-async code such as the thread created
134     /// by `spawn_blocking`.
135     ///
136     /// Another option is [`SyncIoBridge`] for cases where the synchronous context
137     /// is operating on byte streams.  For example, you might use an asynchronous
138     /// HTTP client such as [hyper] to fetch data, but perform complex parsing
139     /// of the payload body using a library written for synchronous I/O.
140     ///
141     /// Finally, see also [Bridging with sync code][bridgesync] for discussions
142     /// around the opposite case of using Tokio as part of a larger synchronous
143     /// codebase.
144     ///
145     /// [`Builder`]: struct@crate::runtime::Builder
146     /// [blocking]: ../index.html#cpu-bound-tasks-and-blocking-code
147     /// [rayon]: https://docs.rs/rayon
148     /// [`mpsc channel`]: crate::sync::mpsc
149     /// [`SyncIoBridge`]: https://docs.rs/tokio-util/latest/tokio_util/io/struct.SyncIoBridge.html
150     /// [hyper]: https://docs.rs/hyper
151     /// [`thread::spawn`]: fn@std::thread::spawn
152     /// [`shutdown_timeout`]: fn@crate::runtime::Runtime::shutdown_timeout
153     /// [bridgesync]: https://tokio.rs/tokio/topics/bridging
154     /// [`AtomicBool`]: struct@std::sync::atomic::AtomicBool
155     ///
156     /// # Examples
157     ///
158     /// Pass an input value and receive result of computation:
159     ///
160     /// ```
161     /// use tokio::task;
162     ///
163     /// # async fn docs() -> Result<(), Box<dyn std::error::Error>>{
164     /// // Initial input
165     /// let mut v = "Hello, ".to_string();
166     /// let res = task::spawn_blocking(move || {
167     ///     // Stand-in for compute-heavy work or using synchronous APIs
168     ///     v.push_str("world");
169     ///     // Pass ownership of the value back to the asynchronous context
170     ///     v
171     /// }).await?;
172     ///
173     /// // `res` is the value returned from the thread
174     /// assert_eq!(res.as_str(), "Hello, world");
175     /// # Ok(())
176     /// # }
177     /// ```
178     ///
179     /// Use a channel:
180     ///
181     /// ```
182     /// use tokio::task;
183     /// use tokio::sync::mpsc;
184     ///
185     /// # async fn docs() {
186     /// let (tx, mut rx) = mpsc::channel(2);
187     /// let start = 5;
188     /// let worker = task::spawn_blocking(move || {
189     ///     for x in 0..10 {
190     ///         // Stand in for complex computation
191     ///         tx.blocking_send(start + x).unwrap();
192     ///     }
193     /// });
194     ///
195     /// let mut acc = 0;
196     /// while let Some(v) = rx.recv().await {
197     ///     acc += v;
198     /// }
199     /// assert_eq!(acc, 95);
200     /// worker.await.unwrap();
201     /// # }
202     /// ```
203     #[track_caller]
204     pub fn spawn_blocking<F, R>(f: F) -> JoinHandle<R>
205     where
206         F: FnOnce() -> R + Send + 'static,
207         R: Send + 'static,
208     {
209         crate::runtime::spawn_blocking(f)
210     }
211 }
212