-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
rt: add tokio::task::Builder (#3881)
Adds a builder API for spawning tasks. Initially, this enables the caller to name the spawned task in order to provide better visibility into all tasks in the system.
- Loading branch information
Showing
7 changed files
with
219 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
#![allow(unreachable_pub)] | ||
use crate::util::error::CONTEXT_MISSING_ERROR; | ||
use crate::{runtime::context, task::JoinHandle}; | ||
use std::future::Future; | ||
|
||
/// Factory which is used to configure the properties of a new task. | ||
/// | ||
/// Methods can be chained in order to configure it. | ||
/// | ||
/// Currently, there is only one configuration option: | ||
/// | ||
/// - [`name`], which specifies an associated name for | ||
/// the task | ||
/// | ||
/// There are three types of task that can be spawned from a Builder: | ||
/// - [`spawn_local`] for executing futures on the current thread | ||
/// - [`spawn`] for executing [`Send`] futures on the runtime | ||
/// - [`spawn_blocking`] for executing blocking code in the | ||
/// blocking thread pool. | ||
/// | ||
/// ## Example | ||
/// | ||
/// ```no_run | ||
/// use tokio::net::{TcpListener, TcpStream}; | ||
/// | ||
/// use std::io; | ||
/// | ||
/// async fn process(socket: TcpStream) { | ||
/// // ... | ||
/// # drop(socket); | ||
/// } | ||
/// | ||
/// #[tokio::main] | ||
/// async fn main() -> io::Result<()> { | ||
/// let listener = TcpListener::bind("127.0.0.1:8080").await?; | ||
/// | ||
/// loop { | ||
/// let (socket, _) = listener.accept().await?; | ||
/// | ||
/// tokio::task::Builder::new() | ||
/// .name("tcp connection handler") | ||
/// .spawn(async move { | ||
/// // Process each socket concurrently. | ||
/// process(socket).await | ||
/// }); | ||
/// } | ||
/// } | ||
/// ``` | ||
#[derive(Default, Debug)] | ||
pub struct Builder<'a> { | ||
name: Option<&'a str>, | ||
} | ||
|
||
impl<'a> Builder<'a> { | ||
/// Creates a new task builder. | ||
pub fn new() -> Self { | ||
Self::default() | ||
} | ||
|
||
/// Assigns a name to the task which will be spawned. | ||
pub fn name(&self, name: &'a str) -> Self { | ||
Self { name: Some(name) } | ||
} | ||
|
||
/// Spawns a task on the executor. | ||
/// | ||
/// See [`task::spawn`](crate::task::spawn) for | ||
/// more details. | ||
#[cfg_attr(tokio_track_caller, track_caller)] | ||
pub fn spawn<Fut>(self, future: Fut) -> JoinHandle<Fut::Output> | ||
where | ||
Fut: Future + Send + 'static, | ||
Fut::Output: Send + 'static, | ||
{ | ||
super::spawn::spawn_inner(future, self.name) | ||
} | ||
|
||
/// Spawns a task on the current thread. | ||
/// | ||
/// See [`task::spawn_local`](crate::task::spawn_local) | ||
/// for more details. | ||
#[cfg_attr(tokio_track_caller, track_caller)] | ||
pub fn spawn_local<Fut>(self, future: Fut) -> JoinHandle<Fut::Output> | ||
where | ||
Fut: Future + 'static, | ||
Fut::Output: 'static, | ||
{ | ||
super::local::spawn_local_inner(future, self.name) | ||
} | ||
|
||
/// Spawns blocking code on the blocking threadpool. | ||
/// | ||
/// See [`task::spawn_blocking`](crate::task::spawn_blocking) | ||
/// for more details. | ||
#[cfg_attr(tokio_track_caller, track_caller)] | ||
pub fn spawn_blocking<Function, Output>(self, function: Function) -> JoinHandle<Output> | ||
where | ||
Function: FnOnce() -> Output + Send + 'static, | ||
Output: Send + 'static, | ||
{ | ||
context::current() | ||
.expect(CONTEXT_MISSING_ERROR) | ||
.spawn_blocking_inner(function, self.name) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
#[cfg(all(tokio_unstable, feature = "tracing"))] | ||
mod tests { | ||
use std::rc::Rc; | ||
use tokio::{ | ||
task::{Builder, LocalSet}, | ||
test, | ||
}; | ||
|
||
#[test] | ||
async fn spawn_with_name() { | ||
let result = Builder::new() | ||
.name("name") | ||
.spawn(async { "task executed" }) | ||
.await; | ||
|
||
assert_eq!(result.unwrap(), "task executed"); | ||
} | ||
|
||
#[test] | ||
async fn spawn_blocking_with_name() { | ||
let result = Builder::new() | ||
.name("name") | ||
.spawn_blocking(|| "task executed") | ||
.await; | ||
|
||
assert_eq!(result.unwrap(), "task executed"); | ||
} | ||
|
||
#[test] | ||
async fn spawn_local_with_name() { | ||
let unsend_data = Rc::new("task executed"); | ||
let result = LocalSet::new() | ||
.run_until(async move { | ||
Builder::new() | ||
.name("name") | ||
.spawn_local(async move { unsend_data }) | ||
.await | ||
}) | ||
.await; | ||
|
||
assert_eq!(*result.unwrap(), "task executed"); | ||
} | ||
|
||
#[test] | ||
async fn spawn_without_name() { | ||
let result = Builder::new().spawn(async { "task executed" }).await; | ||
|
||
assert_eq!(result.unwrap(), "task executed"); | ||
} | ||
|
||
#[test] | ||
async fn spawn_blocking_without_name() { | ||
let result = Builder::new().spawn_blocking(|| "task executed").await; | ||
|
||
assert_eq!(result.unwrap(), "task executed"); | ||
} | ||
|
||
#[test] | ||
async fn spawn_local_without_name() { | ||
let unsend_data = Rc::new("task executed"); | ||
let result = LocalSet::new() | ||
.run_until(async move { Builder::new().spawn_local(async move { unsend_data }).await }) | ||
.await; | ||
|
||
assert_eq!(*result.unwrap(), "task executed"); | ||
} | ||
} |
8fa29cb
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Possible performance regression was detected for benchmark 'sync_mpsc'.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold
2
.send_large
57841
ns/iter (± 6266
)25250
ns/iter (± 273
)2.29
This comment was automatically generated by workflow using github-action-benchmark.
CC: @tokio-rs/maintainers