parallel_worker/lib.rs
1//! # Parallel Worker
2//!
3//! This crate provides a simple interface for running tasks in parallel.
4//! The Worker structs are used to dispatch tasks to worker threads and collect the results.
5//! You can wait for results or receive currently available results.
6//!
7//! ## Workers
8//! There are three types of workers:
9//! - [`BasicWorker`] is a simple worker that processes tasks in parallel using multiple worker threads.
10//! - [`CancelableWorker`] has additional functionality for optional results and task cancellation during execution.
11//! - [`OrderedWorker`] returns results in the same order as the tasks were added.
12//!
13//! ## Example
14//! Basic example of using a worker to run tasks in parallel using the [`BasicWorker`] struct.
15//! Tasks start executing as soon as they are added. When all threads are busy, tasks are queued until a thread becomes available.
16//! ```rust
17//! use parallel_worker::prelude::*;
18//!
19//! fn main() {
20//! let mut worker = BasicWorker::new(|n| {
21//! // Answer to life, the universe and everything
22//! return 42;
23//! });
24//!
25//! worker.add_task(1);
26//! worker.add_task(2);
27//!
28//! assert_eq!(worker.get_blocking(), Some(42));
29//!
30//! worker.add_tasks(0..10);
31//!
32//! assert_eq!(worker.get_iter_blocking().count(), 11);
33//! }
34//! ```
35//!
36//! ## Tasks can be canceled
37//! If you want to cancel tasks during execution, use [`CancelableWorker`] and call the [`check_if_cancelled!`]
38//! macro in your worker function on a regular basis. Excessive checking will lead to a performance costs.
39//! Canceled tasks will stop executing as soon as they reach a [`check_if_cancelled!`].
40//! Results of canceled tasks will be discarded.
41//! Results of tasks that have already completed will remain unaffected.
42//! ```rust
43//! use parallel_worker::prelude::*;
44//!
45//! # use std::{thread::sleep, time::Duration};
46//! fn main() {
47//! let mut worker = CancelableWorker::new(worker_function);
48//!
49//! worker.add_tasks([1, 2, 3, 4]);
50//!
51//! worker.cancel_tasks();
52//!
53//! assert!(worker.get_blocking().is_none());
54//! }
55//!
56//! fn worker_function(task: u64, state: &State) -> Option<u64> {
57//! loop {
58//! sleep(Duration::from_millis(50));
59//! check_if_cancelled!(state);
60//! }
61//! unreachable!()
62//! }
63//!```
64//! ## Results can be optional
65//! If a worker returns [`None`] the result will be discarded. This feature is available in the [`CancelableWorker`].
66//! ```rust
67//! use parallel_worker::prelude::*;
68//!
69//! fn main() {
70//! let mut worker = CancelableWorker::new(|n: u64, _s: &State| {
71//! if n % 2 == 0 {
72//! Some(n)
73//! } else {
74//! None
75//! }
76//! });
77//!
78//! worker.add_tasks(1..=10);
79//!
80//! assert_eq!(worker.get_iter_blocking().count(), 5);
81//! }
82//! ```
83//!
84//! ## Results can be ordered
85//! If you want to get results in the same order as the tasks were added, use [`OrderedWorker`].
86//! ```rust
87//! use parallel_worker::prelude::*;
88//! # use std::{thread::sleep, time::Duration};
89//!
90//! fn main() {
91//! let mut worker = OrderedWorker::new(|n: u64| {
92//! sleep(std::time::Duration::from_millis(n % 3));
93//! n
94//! });
95//!
96//! worker.add_task(1);
97//! worker.add_task(2);
98//! worker.add_tasks(3..=10);
99//!
100//! assert_eq!(worker.get_vec_blocking(), (1..=10).collect::<Vec<_>>());
101//! }
102//! ```
103
104mod internal;
105pub use internal::State;
106
107mod worker_traits;
108pub use worker_traits::{WorkerInit, WorkerMethods};
109
110mod workers;
111 pub use workers::{BasicWorker, CancelableWorker, OrderedWorker};
112
113pub mod prelude {
114 pub use crate::check_if_cancelled;
115 pub use crate::internal::State;
116 pub use crate::worker_traits::{WorkerInit, WorkerMethods};
117 pub use crate::workers::{
118 BasicWorker, CancelableWorker, OrderedWorker,
119 };
120}