threadpool: update crossbeam dependencies (#874)

This commit is contained in:
Stjepan Glavina
2019-01-30 14:08:43 -08:00
committed by Carl Lerche
parent 11e2af66a8
commit e1a07ce50c
9 changed files with 43 additions and 85 deletions
+3 -4
View File
@@ -22,10 +22,9 @@ categories = ["concurrency", "asynchronous"]
[dependencies] [dependencies]
tokio-executor = { version = "0.1.2", path = "../tokio-executor" } tokio-executor = { version = "0.1.2", path = "../tokio-executor" }
futures = "0.1.19" futures = "0.1.19"
crossbeam = "0.6.0" crossbeam-deque = "0.7.0"
crossbeam-channel = "0.3.3" crossbeam-queue = "0.1.0"
crossbeam-deque = "0.6.1" crossbeam-utils = "0.6.4"
crossbeam-utils = "0.6.2"
num_cpus = "1.2" num_cpus = "1.2"
rand = "0.6" rand = "0.6"
slab = "0.4.1" slab = "0.4.1"
+2 -2
View File
@@ -3,7 +3,6 @@ use config::{Config, MAX_WORKERS};
use park::{BoxPark, BoxedPark, DefaultPark}; use park::{BoxPark, BoxedPark, DefaultPark};
use shutdown::ShutdownTrigger; use shutdown::ShutdownTrigger;
use pool::{Pool, MAX_BACKUP}; use pool::{Pool, MAX_BACKUP};
use task::Queue;
use thread_pool::ThreadPool; use thread_pool::ThreadPool;
use worker::{self, Worker, WorkerId}; use worker::{self, Worker, WorkerId};
@@ -13,6 +12,7 @@ use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use std::cmp::max; use std::cmp::max;
use crossbeam_deque::Injector;
use num_cpus; use num_cpus;
use tokio_executor::Enter; use tokio_executor::Enter;
use tokio_executor::park::Park; use tokio_executor::park::Park;
@@ -414,7 +414,7 @@ impl Builder {
workers.into() workers.into()
}; };
let queue = Arc::new(Queue::new()); let queue = Arc::new(Injector::new());
// Create a trigger that will clean up resources on shutdown. // Create a trigger that will clean up resources on shutdown.
// //
+2 -3
View File
@@ -79,9 +79,8 @@
extern crate tokio_executor; extern crate tokio_executor;
extern crate crossbeam; extern crate crossbeam_deque;
extern crate crossbeam_channel; extern crate crossbeam_queue;
extern crate crossbeam_deque as deque;
extern crate crossbeam_utils; extern crate crossbeam_utils;
#[macro_use] #[macro_use]
extern crate futures; extern crate futures;
+4 -3
View File
@@ -15,7 +15,7 @@ use self::backup_stack::BackupStack;
use config::Config; use config::Config;
use shutdown::ShutdownTrigger; use shutdown::ShutdownTrigger;
use task::{Blocking, Queue, Task}; use task::{Blocking, Task};
use worker::{self, Worker, WorkerId}; use worker::{self, Worker, WorkerId};
use futures::Poll; use futures::Poll;
@@ -27,6 +27,7 @@ use std::sync::atomic::AtomicUsize;
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
use std::thread; use std::thread;
use crossbeam_deque::Injector;
use crossbeam_utils::CachePadded; use crossbeam_utils::CachePadded;
use rand; use rand;
@@ -57,7 +58,7 @@ pub(crate) struct Pool {
// //
// Spawned tasks are pushed into this queue. Although worker threads have their own dedicated // Spawned tasks are pushed into this queue. Although worker threads have their own dedicated
// task queues, they periodically steal tasks from this global queue, too. // task queues, they periodically steal tasks from this global queue, too.
pub queue: Arc<Queue>, pub queue: Arc<Injector<Arc<Task>>>,
// Completes the shutdown process when the `ThreadPool` and all `Worker`s get dropped. // Completes the shutdown process when the `ThreadPool` and all `Worker`s get dropped.
// //
@@ -90,7 +91,7 @@ impl Pool {
trigger: Weak<ShutdownTrigger>, trigger: Weak<ShutdownTrigger>,
max_blocking: usize, max_blocking: usize,
config: Config, config: Config,
queue: Arc<Queue>, queue: Arc<Injector<Arc<Task>>>,
) -> Pool { ) -> Pool {
let pool_size = workers.len(); let pool_size = workers.len();
let total_size = max_blocking + pool_size; let total_size = max_blocking + pool_size;
+8 -4
View File
@@ -1,6 +1,7 @@
use task::Queue; use task::Task;
use worker; use worker;
use crossbeam_deque::Injector;
use futures::{Future, Poll, Async}; use futures::{Future, Poll, Async};
use futures::task::AtomicTask; use futures::task::AtomicTask;
@@ -62,14 +63,17 @@ impl Future for Shutdown {
pub(crate) struct ShutdownTrigger { pub(crate) struct ShutdownTrigger {
inner: Arc<Mutex<Inner>>, inner: Arc<Mutex<Inner>>,
workers: Arc<[worker::Entry]>, workers: Arc<[worker::Entry]>,
queue: Arc<Queue>, queue: Arc<Injector<Arc<Task>>>,
} }
unsafe impl Send for ShutdownTrigger {} unsafe impl Send for ShutdownTrigger {}
unsafe impl Sync for ShutdownTrigger {} unsafe impl Sync for ShutdownTrigger {}
impl ShutdownTrigger { impl ShutdownTrigger {
pub(crate) fn new(workers: Arc<[worker::Entry]>, queue: Arc<Queue>) -> ShutdownTrigger { pub(crate) fn new(
workers: Arc<[worker::Entry]>,
queue: Arc<Injector<Arc<Task>>>,
) -> ShutdownTrigger {
ShutdownTrigger { ShutdownTrigger {
inner: Arc::new(Mutex::new(Inner { inner: Arc::new(Mutex::new(Inner {
task: AtomicTask::new(), task: AtomicTask::new(),
@@ -84,7 +88,7 @@ impl ShutdownTrigger {
impl Drop for ShutdownTrigger { impl Drop for ShutdownTrigger {
fn drop(&mut self) { fn drop(&mut self) {
// Drain the global task queue. // Drain the global task queue.
while self.queue.pop().is_some() {} while !self.queue.steal().is_empty() {}
// Drop the remaining incomplete tasks and parkers assosicated with workers. // Drop the remaining incomplete tasks and parkers assosicated with workers.
for worker in self.workers.iter() { for worker in self.workers.iter() {
-2
View File
@@ -1,10 +1,8 @@
mod blocking; mod blocking;
mod blocking_state; mod blocking_state;
mod queue;
mod state; mod state;
pub(crate) use self::blocking::{Blocking, CanBlock}; pub(crate) use self::blocking::{Blocking, CanBlock};
pub(crate) use self::queue::Queue;
use self::blocking_state::BlockingState; use self::blocking_state::BlockingState;
use self::state::State; use self::state::State;
-34
View File
@@ -1,34 +0,0 @@
use task::Task;
use std::sync::Arc;
use crossbeam_channel::{unbounded, Receiver, Sender};
#[derive(Debug)]
pub(crate) struct Queue {
// TODO(stjepang): Use a custom, faster MPMC queue implementation that supports `steal_many()`.
chan: (Sender<Arc<Task>>, Receiver<Arc<Task>>),
}
// ===== impl Queue =====
impl Queue {
/// Create a new, empty, `Queue`.
pub fn new() -> Queue {
Queue {
chan: unbounded(),
}
}
/// Push a task onto the queue.
#[inline]
pub fn push(&self, task: Arc<Task>) {
self.chan.0.send(task).unwrap();
}
/// Pop a task from the queue.
#[inline]
pub fn pop(&self) -> Option<Arc<Task>> {
self.chan.1.try_recv().ok()
}
}
+11 -19
View File
@@ -9,9 +9,9 @@ use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::atomic::Ordering::{Acquire, AcqRel, Relaxed, Release}; use std::sync::atomic::Ordering::{Acquire, AcqRel, Relaxed, Release};
use std::time::Duration; use std::time::Duration;
use crossbeam::queue::SegQueue; use crossbeam_deque::{Steal, Stealer, Worker};
use crossbeam_queue::SegQueue;
use crossbeam_utils::CachePadded; use crossbeam_utils::CachePadded;
use deque;
use slab::Slab; use slab::Slab;
// TODO: None of the fields should be public // TODO: None of the fields should be public
@@ -29,10 +29,10 @@ pub(crate) struct WorkerEntry {
next_sleeper: UnsafeCell<usize>, next_sleeper: UnsafeCell<usize>,
// Worker half of deque // Worker half of deque
worker: deque::Worker<Arc<Task>>, pub worker: Worker<Arc<Task>>,
// Stealer half of deque // Stealer half of deque
stealer: deque::Stealer<Arc<Task>>, stealer: Stealer<Arc<Task>>,
// Thread parker // Thread parker
park: UnsafeCell<Option<BoxPark>>, park: UnsafeCell<Option<BoxPark>>,
@@ -53,7 +53,8 @@ pub(crate) struct WorkerEntry {
impl WorkerEntry { impl WorkerEntry {
pub fn new(park: BoxPark, unpark: BoxUnpark) -> Self { pub fn new(park: BoxPark, unpark: BoxUnpark) -> Self {
let (w, s) = deque::fifo(); let w = Worker::new_fifo();
let s = w.stealer();
WorkerEntry { WorkerEntry {
state: CachePadded::new(AtomicUsize::new(State::default().into())), state: CachePadded::new(AtomicUsize::new(State::default().into())),
@@ -187,7 +188,7 @@ impl WorkerEntry {
/// This **must** only be called by the thread that owns the worker entry. /// This **must** only be called by the thread that owns the worker entry.
/// This function is not `Sync`. /// This function is not `Sync`.
#[inline] #[inline]
pub fn pop_task(&self) -> deque::Pop<Arc<Task>> { pub fn pop_task(&self) -> Option<Arc<Task>> {
self.worker.pop() self.worker.pop()
} }
@@ -199,23 +200,15 @@ impl WorkerEntry {
/// At the same time, this method steals some additional tasks and moves /// At the same time, this method steals some additional tasks and moves
/// them into `dest` in order to balance the work distribution among /// them into `dest` in order to balance the work distribution among
/// workers. /// workers.
pub fn steal_tasks(&self, dest: &Self) -> deque::Steal<Arc<Task>> { pub fn steal_tasks(&self, dest: &Self) -> Steal<Arc<Task>> {
self.stealer.steal_many(&dest.worker) self.stealer.steal_batch_and_pop(&dest.worker)
} }
/// Drain (and drop) all tasks that are queued for work. /// Drain (and drop) all tasks that are queued for work.
/// ///
/// This is called when the pool is shutting down. /// This is called when the pool is shutting down.
pub fn drain_tasks(&self) { pub fn drain_tasks(&self) {
use deque::Pop::*; while self.worker.pop().is_some() {}
loop {
match self.worker.pop() {
Data(_) => {}
Empty => break,
Retry => {}
}
}
} }
/// Parks the worker thread. /// Parks the worker thread.
@@ -284,7 +277,6 @@ impl WorkerEntry {
} }
running_tasks.clear(); running_tasks.clear();
// Drop the parker.
unsafe { unsafe {
*self.park.get() = None; *self.park.get() = None;
*self.unpark.get() = None; *self.unpark.get() = None;
@@ -297,7 +289,7 @@ impl WorkerEntry {
if self.needs_drain.compare_and_swap(true, false, Acquire) { if self.needs_drain.compare_and_swap(true, false, Acquire) {
let running_tasks = unsafe { &mut *self.running_tasks.get() }; let running_tasks = unsafe { &mut *self.running_tasks.get() };
while let Some(task) = self.remotely_completed_tasks.try_pop() { while let Ok(task) = self.remotely_completed_tasks.pop() {
running_tasks.remove(task.reg_index.get()); running_tasks.remove(task.reg_index.get());
} }
} }
+13 -14
View File
@@ -386,16 +386,13 @@ impl Worker {
/// ///
/// Returns `true` if work was found. /// Returns `true` if work was found.
fn try_run_owned_task(&self, notify: &Arc<Notifier>) -> bool { fn try_run_owned_task(&self, notify: &Arc<Notifier>) -> bool {
use deque::Pop;
// Poll the internal queue for a task to run // Poll the internal queue for a task to run
match self.entry().pop_task() { match self.entry().pop_task() {
Pop::Data(task) => { Some(task) => {
self.run_task(task, notify); self.run_task(task, notify);
true true
} }
Pop::Empty => false, None => false,
Pop::Retry => true,
} }
} }
@@ -403,7 +400,7 @@ impl Worker {
/// ///
/// Returns `true` if work was found /// Returns `true` if work was found
fn try_steal_task(&self, notify: &Arc<Notifier>) -> bool { fn try_steal_task(&self, notify: &Arc<Notifier>) -> bool {
use deque::Steal; use crossbeam_deque::Steal;
debug_assert!(!self.is_blocking.get()); debug_assert!(!self.is_blocking.get());
@@ -415,7 +412,7 @@ impl Worker {
loop { loop {
if idx < len { if idx < len {
match self.pool.workers[idx].steal_tasks(self.entry()) { match self.pool.workers[idx].steal_tasks(self.entry()) {
Steal::Data(task) => { Steal::Success(task) => {
trace!("stole task from another worker"); trace!("stole task from another worker");
self.run_task(task, notify); self.run_task(task, notify);
@@ -701,15 +698,17 @@ impl Worker {
/// ///
/// Returns `true` if this worker has tasks in its queue. /// Returns `true` if this worker has tasks in its queue.
fn sleep_light(&self) { fn sleep_light(&self) {
const STEAL_COUNT: usize = 32;
self.entry().park_timeout(Duration::from_millis(0)); self.entry().park_timeout(Duration::from_millis(0));
for _ in 0..STEAL_COUNT { use crossbeam_deque::Steal;
if let Some(task) = self.pool.queue.pop() { loop {
self.pool.submit(task, &self.pool); match self.pool.queue.steal_batch(&self.entry().worker) {
} else { Steal::Success(()) => {
break; self.pool.signal_work(&self.pool);
break;
}
Steal::Empty => break,
Steal::Retry => {}
} }
} }
} }