task: move blocking fns into tokio::task (#1781)

This commit is contained in:
Carl Lerche
2019-11-16 23:35:04 -08:00
committed by GitHub
parent 66cbed3ce3
commit b1d9e55487
7 changed files with 75 additions and 64 deletions
+1 -59
View File
@@ -1,65 +1,7 @@
//! Perform blocking operations from an asynchronous context.
mod pool;
pub(crate) use self::pool::{BlockingPool, Spawner};
pub(crate) use self::pool::{spawn_blocking, BlockingPool, Spawner};
mod schedule;
mod task;
use crate::task::JoinHandle;
/// Run the provided blocking function without blocking the executor.
///
/// In general, issuing a blocking call or performing a lot of compute in a
/// future without yielding is not okay, as it may prevent the executor from
/// driving other futures forward. If you run a closure through this method,
/// the current executor thread will relegate all its executor duties to another
/// (possibly new) thread, and only then poll the task. Note that this requires
/// additional synchronization.
///
/// # Examples
///
/// ```
/// # async fn docs() {
/// tokio::blocking::in_place(move || {
/// // do some compute-heavy work or call synchronous code
/// });
/// # }
/// ```
#[cfg(feature = "rt-full")]
pub fn in_place<F, R>(f: F) -> R
where
F: FnOnce() -> R,
{
use crate::runtime::{enter, thread_pool};
enter::exit(|| thread_pool::block_in_place(f))
}
/// Run the provided closure on a thread where blocking is acceptable.
///
/// In general, issuing a blocking call or performing a lot of compute in a future without
/// yielding is not okay, as it may prevent the executor from driving other futures forward.
/// A closure that is run through this method will instead be run on a dedicated thread pool for
/// such blocking tasks without holding up the main futures executor.
///
/// # Examples
///
/// ```
/// # async fn docs() -> Result<(), Box<dyn std::error::Error>>{
/// let res = tokio::blocking::spawn_blocking(move || {
/// // do some compute-heavy work or call synchronous code
/// "done computing"
/// }).await?;
///
/// assert_eq!(res, "done computing");
/// # Ok(())
/// # }
/// ```
pub fn spawn_blocking<F, R>(f: F) -> JoinHandle<R>
where
F: FnOnce() -> R + Send + 'static,
R: Send + 'static,
{
pool::spawn(f)
}
+1 -1
View File
@@ -53,7 +53,7 @@ const MAX_THREADS: u32 = 1_000;
const KEEP_ALIVE: Duration = Duration::from_secs(10);
/// Run the provided function on an executor dedicated to blocking operations.
pub(super) fn spawn<F, R>(func: F) -> JoinHandle<R>
pub(crate) fn spawn_blocking<F, R>(func: F) -> JoinHandle<R>
where
F: FnOnce() -> R + Send + 'static,
{
+1 -1
View File
@@ -90,7 +90,7 @@ macro_rules! ready {
mod tests;
#[cfg(feature = "blocking")]
pub mod blocking;
pub(crate) mod blocking;
#[cfg(feature = "fs")]
pub mod fs;
@@ -50,7 +50,7 @@ fn only_blocking() {
let (block_tx, block_rx) = oneshot::channel();
pool.spawn(async move {
crate::blocking::in_place(move || {
crate::task::block_in_place(move || {
block_tx.send(());
})
});
@@ -72,7 +72,7 @@ fn blocking_and_regular() {
let done_tx = Arc::new(Mutex::new(Some(done_tx)));
pool.spawn(async move {
crate::blocking::in_place(move || {
crate::task::block_in_place(move || {
block_tx.send(());
})
});
+62
View File
@@ -0,0 +1,62 @@
use crate::blocking;
use crate::task::JoinHandle;
/// Run the provided blocking function without blocking the executor.
///
/// In general, issuing a blocking call or performing a lot of compute in a
/// future without yielding is not okay, as it may prevent the executor from
/// driving other futures forward. If you run a closure through this method,
/// the current executor thread will relegate all its executor duties to another
/// (possibly new) thread, and only then poll the task. Note that this requires
/// additional synchronization.
///
/// # Examples
///
/// ```
/// use tokio::task;
///
/// # async fn docs() {
/// task::block_in_place(move || {
/// // do some compute-heavy work or call synchronous code
/// });
/// # }
/// ```
#[cfg(feature = "rt-full")]
pub fn block_in_place<F, R>(f: F) -> R
where
F: FnOnce() -> R,
{
use crate::runtime::{enter, thread_pool};
enter::exit(|| thread_pool::block_in_place(f))
}
/// Run the provided closure on a thread where blocking is acceptable.
///
/// In general, issuing a blocking call or performing a lot of compute in a future without
/// yielding is not okay, as it may prevent the executor from driving other futures forward.
/// A closure that is run through this method will instead be run on a dedicated thread pool for
/// such blocking tasks without holding up the main futures executor.
///
/// # Examples
///
/// ```
/// use tokio::task;
///
/// # async fn docs() -> Result<(), Box<dyn std::error::Error>>{
/// let res = task::spawn_blocking(move || {
/// // do some compute-heavy work or call synchronous code
/// "done computing"
/// }).await?;
///
/// assert_eq!(res, "done computing");
/// # Ok(())
/// # }
/// ```
pub fn spawn_blocking<F, R>(f: F) -> JoinHandle<R>
where
F: FnOnce() -> R + Send + 'static,
R: Send + 'static,
{
blocking::spawn_blocking(f)
}
+7
View File
@@ -1,5 +1,12 @@
//! Asynchronous green-threads.
#[cfg(feature = "blocking")]
mod blocking;
#[cfg(feature = "rt-full")]
pub use blocking::block_in_place;
#[cfg(feature = "blocking")]
pub use blocking::spawn_blocking;
mod core;
use self::core::Cell;
pub(crate) use self::core::Header;
+1 -1
View File
@@ -268,7 +268,7 @@ fn blocking() {
for _ in 0..4 {
let block = block.clone();
rt.spawn(async move {
tokio::blocking::in_place(move || {
tokio::task::block_in_place(move || {
block.wait();
block.wait();
})