1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
use num_cpus;
use super::Executable;
use super::TaskQueueSet;
use super::Worker;


/// A thread pool for executing tasks.
///
/// Runner contains a pool of workers, each with it's own thread. As tasks are
/// given to the runner to be executed, the workers execute these tasks.
/// In order to prevent idle workers when there is work to be done, the
/// Runner implement's the work stealling model for parallelism. Idle workers
/// will steal tasks from their siblings in order keep the load distributed,
/// and prevent idle cores.
#[derive(Debug)]
pub struct Runner {
  task_queue_set: TaskQueueSet,
  workers: Vec<Worker>,
}

impl Runner {
  // Create a new task runner
  pub fn new() -> Self {
    Self::with_worker_count(num_cpus::get() + 1)
  }

  pub fn with_worker_count(n: usize) -> Self {
    let task_queue_set = TaskQueueSet::new();
    let workers = (0..n)
      .map(|_| Worker::new(task_queue_set.clone()))
      .collect();

    Self {
      task_queue_set,
      workers,
    }
  }

  // run a task
  pub fn run<T>(&mut self, task: T)
  where
    T: Executable + 'static,
  {
    self.task_queue_set.push_to_rand_queue(Box::new(task));
  }

  // run a task
  pub fn run_all<T>(&mut self, tasks: Vec<T>)
  where
    T: Executable + 'static,
  {
    for task in tasks {
      self.run(task);
    }
  }

  pub fn finish(self) {
    for worker in self.workers {
      worker.finish();
    }
  }
}