mirror of
https://github.com/tokio-rs/tokio.git
synced 2025-10-01 12:20:39 +00:00
Steal multiple tasks from another worker at a time (#534)
* Steal multiple tasks from another worker at a time * Better spinning and failing pop * Update crossbeam-deque and simplify spinning
This commit is contained in:
parent
fd36054ae4
commit
96b556fbff
@ -19,7 +19,7 @@ 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-deque = "0.5.0"
|
crossbeam-deque = "0.6.0"
|
||||||
crossbeam-utils = "0.5.0"
|
crossbeam-utils = "0.5.0"
|
||||||
num_cpus = "1.2"
|
num_cpus = "1.2"
|
||||||
rand = "0.5"
|
rand = "0.5"
|
||||||
|
@ -188,23 +188,34 @@ 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`.
|
||||||
pub fn pop_task(&self) -> Option<Arc<Task>> {
|
pub fn pop_task(&self) -> deque::Pop<Arc<Task>> {
|
||||||
self.worker.pop()
|
self.worker.pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Steal a task
|
/// Steal tasks
|
||||||
///
|
///
|
||||||
/// This is called by *other* workers to steal a task for processing. This
|
/// This is called by *other* workers to steal a task for processing. This
|
||||||
/// function is `Sync`.
|
/// function is `Sync`.
|
||||||
pub fn steal_task(&self) -> Option<Arc<Task>> {
|
///
|
||||||
self.stealer.steal()
|
/// At the same time, this method steals some additional tasks and moves
|
||||||
|
/// them into `dest` in order to balance the work distribution among
|
||||||
|
/// workers.
|
||||||
|
pub fn steal_tasks(&self, dest: &Self) -> deque::Steal<Arc<Task>> {
|
||||||
|
self.stealer.steal_many(&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) {
|
||||||
while let Some(_) = self.worker.pop() {
|
use deque::Pop;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match self.worker.pop() {
|
||||||
|
Pop::Data(_) => {}
|
||||||
|
Pop::Empty => break,
|
||||||
|
Pop::Retry => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,7 +217,7 @@ impl Worker {
|
|||||||
///
|
///
|
||||||
/// This function blocks until the worker is shutting down.
|
/// This function blocks until the worker is shutting down.
|
||||||
pub fn run(&self) {
|
pub fn run(&self) {
|
||||||
const MAX_SPINS: usize = 60;
|
const MAX_SPINS: usize = 3;
|
||||||
const LIGHT_SLEEP_INTERVAL: usize = 32;
|
const LIGHT_SLEEP_INTERVAL: usize = 32;
|
||||||
|
|
||||||
// Get the notifier.
|
// Get the notifier.
|
||||||
@ -256,14 +256,14 @@ impl Worker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !consistent {
|
if !consistent {
|
||||||
thread::yield_now();
|
|
||||||
spin_cnt = 0;
|
spin_cnt = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_cnt += 1;
|
spin_cnt += 1;
|
||||||
|
|
||||||
if spin_cnt < MAX_SPINS {
|
// Yield the thread several times before it actually goes to sleep.
|
||||||
|
if spin_cnt <= MAX_SPINS {
|
||||||
thread::yield_now();
|
thread::yield_now();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -384,13 +384,16 @@ impl Worker {
|
|||||||
///
|
///
|
||||||
/// Returns `true` if work was found.
|
/// Returns `true` if work was found.
|
||||||
fn try_run_owned_task(&self, notify: &Arc<Notifier>, sender: &mut Sender) -> bool {
|
fn try_run_owned_task(&self, notify: &Arc<Notifier>, sender: &mut Sender) -> 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() {
|
||||||
Some(task) => {
|
Pop::Data(task) => {
|
||||||
self.run_task(task, notify, sender);
|
self.run_task(task, notify, sender);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
None => false,
|
Pop::Empty => false,
|
||||||
|
Pop::Retry => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -398,15 +401,19 @@ impl Worker {
|
|||||||
///
|
///
|
||||||
/// Returns `true` if work was found
|
/// Returns `true` if work was found
|
||||||
fn try_steal_task(&self, notify: &Arc<Notifier>, sender: &mut Sender) -> bool {
|
fn try_steal_task(&self, notify: &Arc<Notifier>, sender: &mut Sender) -> bool {
|
||||||
|
use deque::Steal;
|
||||||
|
|
||||||
debug_assert!(!self.is_blocking.get());
|
debug_assert!(!self.is_blocking.get());
|
||||||
|
|
||||||
let len = self.inner.workers.len();
|
let len = self.inner.workers.len();
|
||||||
let mut idx = self.inner.rand_usize() % len;
|
let mut idx = self.inner.rand_usize() % len;
|
||||||
|
let mut found_work = false;
|
||||||
let start = idx;
|
let start = idx;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if idx < len {
|
if idx < len {
|
||||||
if let Some(task) = self.inner.workers[idx].steal_task() {
|
match self.inner.workers[idx].steal_tasks(self.entry()) {
|
||||||
|
Steal::Data(task) => {
|
||||||
trace!("stole task");
|
trace!("stole task");
|
||||||
|
|
||||||
self.run_task(task, notify, sender);
|
self.run_task(task, notify, sender);
|
||||||
@ -422,6 +429,9 @@ impl Worker {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
Steal::Empty => {}
|
||||||
|
Steal::Retry => found_work = true,
|
||||||
|
}
|
||||||
|
|
||||||
idx += 1;
|
idx += 1;
|
||||||
} else {
|
} else {
|
||||||
@ -433,7 +443,7 @@ impl Worker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
false
|
found_work
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_task(&self, task: Arc<Task>, notify: &Arc<Notifier>, sender: &mut Sender) {
|
fn run_task(&self, task: Arc<Task>, notify: &Arc<Notifier>, sender: &mut Sender) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user