Skip to content

Commit 268ed5e

Browse files
authored
task: add more tips + links to spawn_blocking docs (#4150)
1 parent 0c68b89 commit 268ed5e

1 file changed

Lines changed: 58 additions & 3 deletions

File tree

tokio/src/task/blocking.rs

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,27 +112,82 @@ cfg_rt! {
112112
/// still spawn additional threads for blocking operations. The basic
113113
/// scheduler's single thread is only used for asynchronous code.
114114
///
115+
/// # Related APIs and patterns for bridging asynchronous and blocking code
116+
///
117+
/// In simple cases, it is sufficient to have the closure accept input
118+
/// parameters at creation time and return a single value (or struct/tuple, etc.).
119+
///
120+
/// For more complex situations in which it is desirable to stream data to or from
121+
/// the synchronous context, the [`mpsc channel`] has `blocking_send` and
122+
/// `blocking_recv` methods for use in non-async code such as the thread created
123+
/// by `spawn_blocking`.
124+
///
125+
/// Another option is [`SyncIoBridge`] for cases where the synchronous context
126+
/// is operating on byte streams. For example, you might use an asynchronous
127+
/// HTTP client such as [hyper] to fetch data, but perform complex parsing
128+
/// of the payload body using a library written for synchronous I/O.
129+
///
130+
/// Finally, see also [Bridging with sync code][bridgesync] for discussions
131+
/// around the opposite case of using Tokio as part of a larger synchronous
132+
/// codebase.
133+
///
115134
/// [`Builder`]: struct@crate::runtime::Builder
116135
/// [blocking]: ../index.html#cpu-bound-tasks-and-blocking-code
117136
/// [rayon]: https://docs.rs/rayon
137+
/// [`mpsc channel`]: crate::sync::mpsc
138+
/// [`SyncIoBridge`]: https://docs.rs/tokio-util/0.6/tokio_util/io/struct.SyncIoBridge.html
139+
/// [hyper]: https://docs.rs/hyper
118140
/// [`thread::spawn`]: fn@std::thread::spawn
119141
/// [`shutdown_timeout`]: fn@crate::runtime::Runtime::shutdown_timeout
142+
/// [bridgesync]: https://tokio.rs/tokio/topics/bridging
120143
///
121144
/// # Examples
122145
///
146+
/// Pass an input value and receive result of computation:
147+
///
123148
/// ```
124149
/// use tokio::task;
125150
///
126151
/// # async fn docs() -> Result<(), Box<dyn std::error::Error>>{
152+
/// // Initial input
153+
/// let mut v = "Hello, ".to_string();
127154
/// let res = task::spawn_blocking(move || {
128-
/// // do some compute-heavy work or call synchronous code
129-
/// "done computing"
155+
/// // Stand-in for compute-heavy work or using synchronous APIs
156+
/// v.push_str("world");
157+
/// // Pass ownership of the value back to the asynchronous context
158+
/// v
130159
/// }).await?;
131160
///
132-
/// assert_eq!(res, "done computing");
161+
/// // `res` is the value returned from the thread
162+
/// assert_eq!(res.as_str(), "Hello, world");
133163
/// # Ok(())
134164
/// # }
135165
/// ```
166+
///
167+
/// Use a channel:
168+
///
169+
/// ```
170+
/// use tokio::task;
171+
/// use tokio::sync::mpsc;
172+
///
173+
/// # async fn docs() {
174+
/// let (tx, mut rx) = mpsc::channel(2);
175+
/// let start = 5;
176+
/// let worker = task::spawn_blocking(move || {
177+
/// for x in 0..10 {
178+
/// // Stand in for complex computation
179+
/// tx.blocking_send(start + x).unwrap();
180+
/// }
181+
/// });
182+
///
183+
/// let mut acc = 0;
184+
/// while let Some(v) = rx.recv().await {
185+
/// acc += v;
186+
/// }
187+
/// assert_eq!(acc, 95);
188+
/// worker.await.unwrap();
189+
/// # }
190+
/// ```
136191
#[cfg_attr(tokio_track_caller, track_caller)]
137192
pub fn spawn_blocking<F, R>(f: F) -> JoinHandle<R>
138193
where

0 commit comments

Comments
 (0)