@@ -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