mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-08-29 00:00:11 +02:00
task: stabilise JoinMap (#7075)
This commit is contained in:
@@ -21,7 +21,7 @@ categories = ["asynchronous"]
|
|||||||
default = []
|
default = []
|
||||||
|
|
||||||
# Shorthand for enabling everything
|
# Shorthand for enabling everything
|
||||||
full = ["codec", "compat", "io-util", "time", "net", "rt"]
|
full = ["codec", "compat", "io-util", "time", "net", "rt", "join-map"]
|
||||||
|
|
||||||
net = ["tokio/net"]
|
net = ["tokio/net"]
|
||||||
compat = ["futures-io"]
|
compat = ["futures-io"]
|
||||||
@@ -29,7 +29,8 @@ codec = []
|
|||||||
time = ["tokio/time", "slab"]
|
time = ["tokio/time", "slab"]
|
||||||
io = []
|
io = []
|
||||||
io-util = ["io", "tokio/rt", "tokio/io-util"]
|
io-util = ["io", "tokio/rt", "tokio/io-util"]
|
||||||
rt = ["tokio/rt", "tokio/sync", "futures-util", "hashbrown"]
|
rt = ["tokio/rt", "tokio/sync", "futures-util"]
|
||||||
|
join-map = ["rt", "hashbrown"]
|
||||||
|
|
||||||
__docs_rs = ["futures-util"]
|
__docs_rs = ["futures-util"]
|
||||||
|
|
||||||
@@ -43,8 +44,6 @@ futures-util = { version = "0.3.0", optional = true }
|
|||||||
pin-project-lite = "0.2.11"
|
pin-project-lite = "0.2.11"
|
||||||
slab = { version = "0.4.4", optional = true } # Backs `DelayQueue`
|
slab = { version = "0.4.4", optional = true } # Backs `DelayQueue`
|
||||||
tracing = { version = "0.1.29", default-features = false, features = ["std"], optional = true }
|
tracing = { version = "0.1.29", default-features = false, features = ["std"], optional = true }
|
||||||
|
|
||||||
[target.'cfg(tokio_unstable)'.dependencies]
|
|
||||||
hashbrown = { version = "0.15.0", default-features = false, optional = true }
|
hashbrown = { version = "0.15.0", default-features = false, optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|||||||
@@ -45,9 +45,11 @@ cfg_io! {
|
|||||||
|
|
||||||
cfg_rt! {
|
cfg_rt! {
|
||||||
pub mod context;
|
pub mod context;
|
||||||
pub mod task;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "rt")]
|
||||||
|
pub mod task;
|
||||||
|
|
||||||
cfg_time! {
|
cfg_time! {
|
||||||
pub mod time;
|
pub mod time;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,10 +29,6 @@ use tokio::task::{AbortHandle, Id, JoinError, JoinSet, LocalSet};
|
|||||||
///
|
///
|
||||||
/// When the `JoinMap` is dropped, all tasks in the `JoinMap` are immediately aborted.
|
/// When the `JoinMap` is dropped, all tasks in the `JoinMap` are immediately aborted.
|
||||||
///
|
///
|
||||||
/// **Note**: This type depends on Tokio's [unstable API][unstable]. See [the
|
|
||||||
/// documentation on unstable features][unstable] for details on how to enable
|
|
||||||
/// Tokio's unstable features.
|
|
||||||
///
|
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// Spawn multiple tasks and wait for them:
|
/// Spawn multiple tasks and wait for them:
|
||||||
@@ -96,11 +92,9 @@ use tokio::task::{AbortHandle, Id, JoinError, JoinSet, LocalSet};
|
|||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// [`JoinSet`]: tokio::task::JoinSet
|
/// [`JoinSet`]: tokio::task::JoinSet
|
||||||
/// [unstable]: tokio#unstable-features
|
|
||||||
/// [abort]: fn@Self::abort
|
/// [abort]: fn@Self::abort
|
||||||
/// [abort_matching]: fn@Self::abort_matching
|
/// [abort_matching]: fn@Self::abort_matching
|
||||||
/// [contains]: fn@Self::contains_key
|
/// [contains]: fn@Self::contains_key
|
||||||
#[cfg_attr(docsrs, doc(cfg(all(feature = "rt", tokio_unstable))))]
|
|
||||||
pub struct JoinMap<K, V, S = RandomState> {
|
pub struct JoinMap<K, V, S = RandomState> {
|
||||||
/// A map of the [`AbortHandle`]s of the tasks spawned on this `JoinMap`,
|
/// A map of the [`AbortHandle`]s of the tasks spawned on this `JoinMap`,
|
||||||
/// indexed by their keys.
|
/// indexed by their keys.
|
||||||
@@ -541,9 +535,9 @@ where
|
|||||||
/// assert!(!map.abort("goodbye universe"));
|
/// assert!(!map.abort("goodbye universe"));
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn abort<Q: ?Sized>(&mut self, key: &Q) -> bool
|
pub fn abort<Q>(&mut self, key: &Q) -> bool
|
||||||
where
|
where
|
||||||
Q: Hash + Eq,
|
Q: ?Sized + Hash + Eq,
|
||||||
K: Borrow<Q>,
|
K: Borrow<Q>,
|
||||||
{
|
{
|
||||||
match self.get_by_key(key) {
|
match self.get_by_key(key) {
|
||||||
@@ -638,9 +632,9 @@ where
|
|||||||
/// call to [`join_next`], this method will still return `true`.
|
/// call to [`join_next`], this method will still return `true`.
|
||||||
///
|
///
|
||||||
/// [`join_next`]: fn@Self::join_next
|
/// [`join_next`]: fn@Self::join_next
|
||||||
pub fn contains_key<Q: ?Sized>(&self, key: &Q) -> bool
|
pub fn contains_key<Q>(&self, key: &Q) -> bool
|
||||||
where
|
where
|
||||||
Q: Hash + Eq,
|
Q: ?Sized + Hash + Eq,
|
||||||
K: Borrow<Q>,
|
K: Borrow<Q>,
|
||||||
{
|
{
|
||||||
self.get_by_key(key).is_some()
|
self.get_by_key(key).is_some()
|
||||||
@@ -744,9 +738,9 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Look up a task in the map by its key, returning the key and abort handle.
|
/// Look up a task in the map by its key, returning the key and abort handle.
|
||||||
fn get_by_key<'map, Q: ?Sized>(&'map self, key: &Q) -> Option<&'map (K, AbortHandle)>
|
fn get_by_key<'map, Q>(&'map self, key: &Q) -> Option<&'map (K, AbortHandle)>
|
||||||
where
|
where
|
||||||
Q: Hash + Eq,
|
Q: ?Sized + Hash + Eq,
|
||||||
K: Borrow<Q>,
|
K: Borrow<Q>,
|
||||||
{
|
{
|
||||||
let hash_builder = self.hashes_by_task.hasher();
|
let hash_builder = self.hashes_by_task.hasher();
|
||||||
@@ -774,9 +768,10 @@ where
|
|||||||
|
|
||||||
/// Returns the hash for a given key.
|
/// Returns the hash for a given key.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn hash_one<S: BuildHasher, Q: ?Sized>(hash_builder: &S, key: &Q) -> u64
|
fn hash_one<S, Q>(hash_builder: &S, key: &Q) -> u64
|
||||||
where
|
where
|
||||||
Q: Hash,
|
Q: ?Sized + Hash,
|
||||||
|
S: BuildHasher,
|
||||||
{
|
{
|
||||||
let mut hasher = hash_builder.build_hasher();
|
let mut hasher = hash_builder.build_hasher();
|
||||||
key.hash(&mut hasher);
|
key.hash(&mut hasher);
|
||||||
|
|||||||
+17
-12
@@ -1,16 +1,21 @@
|
|||||||
//! Extra utilities for spawning tasks
|
//! Extra utilities for spawning tasks
|
||||||
|
//!
|
||||||
|
//! This module is only available when the `rt` feature is enabled. Note that enabling the
|
||||||
|
//! `join-map` feature will automatically also enable the `rt` feature.
|
||||||
|
|
||||||
#[cfg(tokio_unstable)]
|
cfg_rt! {
|
||||||
|
mod spawn_pinned;
|
||||||
|
pub use spawn_pinned::LocalPoolHandle;
|
||||||
|
|
||||||
|
pub mod task_tracker;
|
||||||
|
pub use task_tracker::TaskTracker;
|
||||||
|
|
||||||
|
mod abort_on_drop;
|
||||||
|
pub use abort_on_drop::AbortOnDropHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "join-map")]
|
||||||
mod join_map;
|
mod join_map;
|
||||||
mod spawn_pinned;
|
#[cfg(feature = "join-map")]
|
||||||
pub use spawn_pinned::LocalPoolHandle;
|
#[cfg_attr(docsrs, doc(cfg(feature = "join-map")))]
|
||||||
|
|
||||||
#[cfg(tokio_unstable)]
|
|
||||||
#[cfg_attr(docsrs, doc(cfg(all(tokio_unstable, feature = "rt"))))]
|
|
||||||
pub use join_map::{JoinMap, JoinMapKeys};
|
pub use join_map::{JoinMap, JoinMapKeys};
|
||||||
|
|
||||||
pub mod task_tracker;
|
|
||||||
pub use task_tracker::TaskTracker;
|
|
||||||
|
|
||||||
mod abort_on_drop;
|
|
||||||
pub use abort_on_drop::AbortOnDropHandle;
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#![warn(rust_2018_idioms)]
|
#![warn(rust_2018_idioms)]
|
||||||
#![cfg(all(feature = "rt", tokio_unstable))]
|
#![cfg(feature = "join-map")]
|
||||||
|
|
||||||
use std::panic::AssertUnwindSafe;
|
use std::panic::AssertUnwindSafe;
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ async fn test_with_sleep() {
|
|||||||
map.detach_all();
|
map.detach_all();
|
||||||
assert_eq!(map.len(), 0);
|
assert_eq!(map.len(), 0);
|
||||||
|
|
||||||
assert!(matches!(map.join_next().await, None));
|
assert!(map.join_next().await.is_none());
|
||||||
|
|
||||||
for i in 0..10 {
|
for i in 0..10 {
|
||||||
map.spawn(i, async move {
|
map.spawn(i, async move {
|
||||||
@@ -45,7 +45,7 @@ async fn test_with_sleep() {
|
|||||||
for was_seen in &seen {
|
for was_seen in &seen {
|
||||||
assert!(was_seen);
|
assert!(was_seen);
|
||||||
}
|
}
|
||||||
assert!(matches!(map.join_next().await, None));
|
assert!(map.join_next().await.is_none());
|
||||||
|
|
||||||
// Do it again.
|
// Do it again.
|
||||||
for i in 0..10 {
|
for i in 0..10 {
|
||||||
@@ -64,7 +64,7 @@ async fn test_with_sleep() {
|
|||||||
for was_seen in &seen {
|
for was_seen in &seen {
|
||||||
assert!(was_seen);
|
assert!(was_seen);
|
||||||
}
|
}
|
||||||
assert!(matches!(map.join_next().await, None));
|
assert!(map.join_next().await.is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -250,7 +250,7 @@ async fn join_map_coop() {
|
|||||||
loop {
|
loop {
|
||||||
match map.join_next().now_or_never() {
|
match map.join_next().now_or_never() {
|
||||||
Some(Some((key, Ok(i)))) => assert_eq!(key, i),
|
Some(Some((key, Ok(i)))) => assert_eq!(key, i),
|
||||||
Some(Some((key, Err(err)))) => panic!("failed[{}]: {}", key, err),
|
Some(Some((key, Err(err)))) => panic!("failed[{key}]: {err}"),
|
||||||
None => {
|
None => {
|
||||||
coop_count += 1;
|
coop_count += 1;
|
||||||
tokio::task::yield_now().await;
|
tokio::task::yield_now().await;
|
||||||
|
|||||||
Reference in New Issue
Block a user