| 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 | /// Be aware that tasks spawned using `spawn_blocking` cannot be aborted |
| 107 | /// because they are not async. If you call [`abort`] on a `spawn_blocking` |
| 108 | /// task, then this *will not have any effect*, and the task will continue |
| 109 | /// running normally. The exception is if the task has not started running |
| 110 | /// yet; in that case, calling `abort` may prevent the task from starting. |
| 111 | /// |
| 112 | /// When you shut down the executor, it will wait indefinitely for all blocking operations to |
| 113 | /// finish. You can use [`shutdown_timeout`] to stop waiting for them after a |
| 114 | /// certain timeout. Be aware that this will still not cancel the tasks — they |
| 115 | /// are simply allowed to keep running after the method returns. It is possible |
| 116 | /// for a blocking task to be cancelled if it has not yet started running, but this |
| 117 | /// is not guaranteed. |
| 118 | /// |
| 119 | /// Note that if you are using the single threaded runtime, this function will |
| 120 | /// still spawn additional threads for blocking operations. The current-thread |
| 121 | /// scheduler's single thread is only used for asynchronous code. |
| 122 | /// |
| 123 | /// # Related APIs and patterns for bridging asynchronous and blocking code |
| 124 | /// |
| 125 | /// In simple cases, it is sufficient to have the closure accept input |
| 126 | /// parameters at creation time and return a single value (or struct/tuple, etc.). |
| 127 | /// |
| 128 | /// For more complex situations in which it is desirable to stream data to or from |
| 129 | /// the synchronous context, the [`mpsc channel`] has `blocking_send` and |
| 130 | /// `blocking_recv` methods for use in non-async code such as the thread created |
| 131 | /// by `spawn_blocking`. |
| 132 | /// |
| 133 | /// Another option is [`SyncIoBridge`] for cases where the synchronous context |
| 134 | /// is operating on byte streams. For example, you might use an asynchronous |
| 135 | /// HTTP client such as [hyper] to fetch data, but perform complex parsing |
| 136 | /// of the payload body using a library written for synchronous I/O. |
| 137 | /// |
| 138 | /// Finally, see also [Bridging with sync code][bridgesync] for discussions |
| 139 | /// around the opposite case of using Tokio as part of a larger synchronous |
| 140 | /// codebase. |
| 141 | /// |
| 142 | /// [`Builder`]: struct@crate::runtime::Builder |
| 143 | /// [blocking]: ../index.html#cpu-bound-tasks-and-blocking-code |
| 144 | /// [rayon]: https://docs.rs/rayon |
| 145 | /// [`mpsc channel`]: crate::sync::mpsc |
| 146 | /// [`SyncIoBridge`]: https://docs.rs/tokio-util/latest/tokio_util/io/struct.SyncIoBridge.html |
| 147 | /// [hyper]: https://docs.rs/hyper |
| 148 | /// [`thread::spawn`]: fn@std::thread::spawn |
| 149 | /// [`shutdown_timeout`]: fn@crate::runtime::Runtime::shutdown_timeout |
| 150 | /// [bridgesync]: https://tokio.rs/tokio/topics/bridging |
| 151 | /// [`AtomicBool`]: struct@std::sync::atomic::AtomicBool |
| 152 | /// [`abort`]: crate::task::JoinHandle::abort |
| 153 | /// |
| 154 | /// # Examples |
| 155 | /// |
| 156 | /// Pass an input value and receive result of computation: |
| 157 | /// |
| 158 | /// ``` |
| 159 | /// use tokio::task; |
| 160 | /// |
| 161 | /// # async fn docs() -> Result<(), Box<dyn std::error::Error>>{ |
| 162 | /// // Initial input |
| 163 | /// let mut v = "Hello, ".to_string(); |
| 164 | /// let res = task::spawn_blocking(move || { |
| 165 | /// // Stand-in for compute-heavy work or using synchronous APIs |
| 166 | /// v.push_str("world"); |
| 167 | /// // Pass ownership of the value back to the asynchronous context |
| 168 | /// v |
| 169 | /// }).await?; |
| 170 | /// |
| 171 | /// // `res` is the value returned from the thread |
| 172 | /// assert_eq!(res.as_str(), "Hello, world"); |
| 173 | /// # Ok(()) |
| 174 | /// # } |
| 175 | /// ``` |
| 176 | /// |
| 177 | /// Use a channel: |
| 178 | /// |
| 179 | /// ``` |
| 180 | /// use tokio::task; |
| 181 | /// use tokio::sync::mpsc; |
| 182 | /// |
| 183 | /// # async fn docs() { |
| 184 | /// let (tx, mut rx) = mpsc::channel(2); |
| 185 | /// let start = 5; |
| 186 | /// let worker = task::spawn_blocking(move || { |
| 187 | /// for x in 0..10 { |
| 188 | /// // Stand in for complex computation |
| 189 | /// tx.blocking_send(start + x).unwrap(); |
| 190 | /// } |
| 191 | /// }); |
| 192 | /// |
| 193 | /// let mut acc = 0; |
| 194 | /// while let Some(v) = rx.recv().await { |
| 195 | /// acc += v; |
| 196 | /// } |
| 197 | /// assert_eq!(acc, 95); |
| 198 | /// worker.await.unwrap(); |
| 199 | /// # } |
| 200 | /// ``` |
| 201 | #[track_caller ] |
| 202 | pub fn spawn_blocking<F, R>(f: F) -> JoinHandle<R> |
| 203 | where |
| 204 | F: FnOnce() -> R + Send + 'static, |
| 205 | R: Send + 'static, |
| 206 | { |
| 207 | crate::runtime::spawn_blocking(f) |
| 208 | } |
| 209 | } |
| 210 | |