1use crate::{UtilsError, UtilsResult};
7use scirs2_core::numeric::Zero;
8use std::collections::VecDeque;
9use std::sync::{Arc, Mutex};
10use std::thread;
11#[cfg(test)]
12use std::time::Duration;
13
14#[derive(Debug)]
16pub struct ThreadPool {
17 workers: Vec<Worker>,
18 sender: Option<std::sync::mpsc::Sender<Job>>,
19 num_threads: usize,
20}
21
22type Job = Box<dyn FnOnce() + Send + 'static>;
23
24impl ThreadPool {
25 pub fn new(num_threads: usize) -> UtilsResult<Self> {
27 if num_threads == 0 {
28 return Err(UtilsError::InvalidParameter(
29 "Thread pool size must be greater than 0".to_string(),
30 ));
31 }
32
33 let (sender, receiver) = std::sync::mpsc::channel();
34 let receiver = Arc::new(Mutex::new(receiver));
35 let mut workers = Vec::with_capacity(num_threads);
36
37 for id in 0..num_threads {
38 workers.push(Worker::new(id, Arc::clone(&receiver))?);
39 }
40
41 Ok(ThreadPool {
42 workers,
43 sender: Some(sender),
44 num_threads,
45 })
46 }
47
48 pub fn with_cpu_cores() -> UtilsResult<Self> {
50 let num_cores = num_cpus::get();
51 Self::new(num_cores)
52 }
53
54 pub fn execute<F>(&self, f: F) -> UtilsResult<()>
56 where
57 F: FnOnce() + Send + 'static,
58 {
59 let job = Box::new(f);
60 self.sender
61 .as_ref()
62 .ok_or_else(|| {
63 UtilsError::InvalidParameter("Thread pool is shutting down".to_string())
64 })?
65 .send(job)
66 .map_err(|_| {
67 UtilsError::InvalidParameter("Failed to send job to thread pool".to_string())
68 })?;
69 Ok(())
70 }
71
72 pub fn thread_count(&self) -> usize {
74 self.num_threads
75 }
76
77 pub fn join(&mut self) {
79 drop(self.sender.take());
80 for worker in &mut self.workers {
81 if let Some(thread) = worker.thread.take() {
82 thread.join().expect("operation should succeed");
83 }
84 }
85 }
86}
87
88impl Drop for ThreadPool {
89 fn drop(&mut self) {
90 drop(self.sender.take());
91 for worker in &mut self.workers {
92 if let Some(thread) = worker.thread.take() {
93 thread.join().expect("operation should succeed");
94 }
95 }
96 }
97}
98
99#[derive(Debug)]
100struct Worker {
101 #[allow(dead_code)]
102 id: usize,
103 thread: Option<thread::JoinHandle<()>>,
104}
105
106impl Worker {
107 fn new(id: usize, receiver: Arc<Mutex<std::sync::mpsc::Receiver<Job>>>) -> UtilsResult<Self> {
108 let thread = thread::spawn(move || loop {
109 let job = receiver.lock().expect("operation should succeed").recv();
110 match job {
111 Ok(job) => {
112 job();
113 }
114 Err(_) => {
115 break;
116 }
117 }
118 });
119
120 Ok(Worker {
121 id,
122 thread: Some(thread),
123 })
124 }
125}
126
127#[derive(Debug)]
129pub struct WorkStealingQueue<T> {
130 local_queue: Arc<Mutex<VecDeque<T>>>,
131 global_queue: Arc<Mutex<VecDeque<T>>>,
132 workers: Vec<Arc<Mutex<VecDeque<T>>>>,
133 worker_id: usize,
134}
135
136impl<T> WorkStealingQueue<T>
137where
138 T: Send + 'static + Clone,
139{
140 pub fn new(num_workers: usize) -> Self {
142 let global_queue = Arc::new(Mutex::new(VecDeque::new()));
143 let mut workers = Vec::with_capacity(num_workers);
144
145 for _ in 0..num_workers {
146 workers.push(Arc::new(Mutex::new(VecDeque::new())));
147 }
148
149 Self {
150 local_queue: Arc::clone(&workers[0]),
151 global_queue,
152 workers,
153 worker_id: 0,
154 }
155 }
156
157 pub fn push_local(&self, task: T) -> UtilsResult<()> {
159 self.local_queue
160 .lock()
161 .map_err(|_| {
162 UtilsError::InvalidParameter("Failed to acquire local queue lock".to_string())
163 })?
164 .push_back(task);
165 Ok(())
166 }
167
168 pub fn push_global(&self, task: T) -> UtilsResult<()> {
170 self.global_queue
171 .lock()
172 .map_err(|_| {
173 UtilsError::InvalidParameter("Failed to acquire global queue lock".to_string())
174 })?
175 .push_back(task);
176 Ok(())
177 }
178
179 pub fn pop_local(&self) -> UtilsResult<Option<T>> {
181 Ok(self
182 .local_queue
183 .lock()
184 .map_err(|_| {
185 UtilsError::InvalidParameter("Failed to acquire local queue lock".to_string())
186 })?
187 .pop_front())
188 }
189
190 pub fn steal_work(&self) -> UtilsResult<Option<T>> {
192 for (i, worker_queue) in self.workers.iter().enumerate() {
194 if i != self.worker_id {
195 if let Ok(mut queue) = worker_queue.try_lock() {
196 if let Some(task) = queue.pop_back() {
197 return Ok(Some(task));
198 }
199 }
200 }
201 }
202
203 if let Ok(mut global) = self.global_queue.try_lock() {
205 return Ok(global.pop_front());
206 }
207
208 Ok(None)
209 }
210
211 pub fn get_task(&self) -> UtilsResult<Option<T>> {
213 if let Some(task) = self.pop_local()? {
215 return Ok(Some(task));
216 }
217
218 self.steal_work()
220 }
221}
222
223pub struct ParallelIterator<T> {
225 items: Vec<T>,
226 chunk_size: usize,
227}
228
229impl<T> ParallelIterator<T>
230where
231 T: Send + 'static + Clone,
232{
233 pub fn new(items: Vec<T>) -> Self {
235 let chunk_size = (items.len() / num_cpus::get()).max(1);
236 Self { items, chunk_size }
237 }
238
239 pub fn with_chunk_size(mut self, chunk_size: usize) -> Self {
241 self.chunk_size = chunk_size.max(1);
242 self
243 }
244
245 pub fn map<F, R>(self, f: F) -> UtilsResult<Vec<R>>
247 where
248 F: Fn(T) -> R + Send + Sync + 'static,
249 R: Send + 'static + Clone,
250 {
251 let f = Arc::new(f);
252 let results = Arc::new(Mutex::new(Vec::with_capacity(self.items.len())));
253 let _thread_pool = ThreadPool::with_cpu_cores()?;
254
255 let chunks: Vec<_> = self
257 .items
258 .into_iter()
259 .collect::<Vec<_>>()
260 .chunks(self.chunk_size)
261 .map(|chunk| chunk.to_vec())
262 .collect();
263
264 let mut handles = Vec::new();
265
266 for (chunk_idx, chunk) in chunks.into_iter().enumerate() {
267 let f_clone = Arc::clone(&f);
268 let results_clone = Arc::clone(&results);
269 let chunk_size = chunk.len();
270
271 let handle = thread::spawn(move || {
272 let mut chunk_results = Vec::with_capacity(chunk_size);
273 for item in chunk {
274 chunk_results.push(f_clone(item));
275 }
276
277 let mut results_lock = results_clone.lock().expect("operation should succeed");
278 if results_lock.len() <= chunk_idx {
280 results_lock.resize_with(chunk_idx + 1, || Vec::new());
281 }
282 results_lock[chunk_idx] = chunk_results;
283 });
284
285 handles.push(handle);
286 }
287
288 for handle in handles {
290 handle.join().map_err(|_| {
291 UtilsError::InvalidParameter(
292 "Thread panicked during parallel execution".to_string(),
293 )
294 })?;
295 }
296
297 let results_lock = results.lock().expect("operation should succeed");
299 let mut final_results = Vec::new();
300 for chunk_results in results_lock.iter() {
301 final_results.extend_from_slice(chunk_results);
302 }
303
304 Ok(final_results)
305 }
306
307 pub fn filter<F>(self, predicate: F) -> UtilsResult<Vec<T>>
309 where
310 F: Fn(&T) -> bool + Send + Sync + 'static,
311 T: Clone,
312 {
313 let predicate = Arc::new(predicate);
314 let results = Arc::new(Mutex::new(Vec::new()));
315 let _thread_pool = ThreadPool::with_cpu_cores()?;
316
317 let chunks: Vec<_> = self
319 .items
320 .into_iter()
321 .collect::<Vec<_>>()
322 .chunks(self.chunk_size)
323 .map(|chunk| chunk.to_vec())
324 .collect();
325
326 let mut handles = Vec::new();
327
328 for (chunk_idx, chunk) in chunks.into_iter().enumerate() {
329 let predicate_clone = Arc::clone(&predicate);
330 let results_clone = Arc::clone(&results);
331
332 let handle = thread::spawn(move || {
333 let filtered: Vec<T> = chunk
334 .into_iter()
335 .filter(|item| predicate_clone(item))
336 .collect();
337
338 let mut results_lock = results_clone.lock().expect("operation should succeed");
339 if results_lock.len() <= chunk_idx {
341 results_lock.resize_with(chunk_idx + 1, || Vec::new());
342 }
343 results_lock[chunk_idx] = filtered;
344 });
345
346 handles.push(handle);
347 }
348
349 for handle in handles {
351 handle.join().map_err(|_| {
352 UtilsError::InvalidParameter(
353 "Thread panicked during parallel execution".to_string(),
354 )
355 })?;
356 }
357
358 let results_lock = results.lock().expect("operation should succeed");
360 let mut final_results = Vec::new();
361 for chunk_results in results_lock.iter() {
362 final_results.extend_from_slice(chunk_results);
363 }
364
365 Ok(final_results)
366 }
367}
368
369pub struct ParallelReducer;
371
372impl ParallelReducer {
373 pub fn reduce<T, F>(items: Vec<T>, initial: T, op: F) -> UtilsResult<T>
375 where
376 T: Send + Sync + Clone + 'static,
377 F: Fn(T, T) -> T + Send + Sync + 'static,
378 {
379 if items.is_empty() {
380 return Ok(initial);
381 }
382
383 let op = Arc::new(op);
384 let chunk_size = (items.len() / num_cpus::get()).max(1);
385
386 let chunks: Vec<_> = items
388 .chunks(chunk_size)
389 .map(|chunk| chunk.to_vec())
390 .collect();
391
392 let mut handles = Vec::new();
393 let mut partial_results = Vec::new();
394
395 for chunk in chunks.into_iter() {
396 let op_clone = Arc::clone(&op);
397 let initial_clone = initial.clone();
398
399 let handle = thread::spawn(move || {
400 chunk
401 .into_iter()
402 .fold(initial_clone, |acc, item| op_clone(acc, item))
403 });
404
405 handles.push(handle);
406 }
407
408 for handle in handles {
410 let result = handle.join().map_err(|_| {
411 UtilsError::InvalidParameter(
412 "Thread panicked during parallel reduction".to_string(),
413 )
414 })?;
415 partial_results.push(result);
416 }
417
418 Ok(partial_results
420 .into_iter()
421 .fold(initial, |acc, partial| op(acc, partial)))
422 }
423
424 pub fn sum<T>(items: Vec<T>) -> UtilsResult<T>
426 where
427 T: Send + Sync + Clone + std::ops::Add<Output = T> + Zero + 'static,
428 {
429 Self::reduce(items, T::zero(), |a, b| a + b)
430 }
431
432 pub fn min<T>(items: Vec<T>) -> UtilsResult<Option<T>>
434 where
435 T: Send + Sync + Clone + Ord + 'static,
436 {
437 if items.is_empty() {
438 return Ok(None);
439 }
440
441 let first = items[0].clone();
442 let result = Self::reduce(items, first, |a, b| if a < b { a } else { b })?;
443 Ok(Some(result))
444 }
445
446 pub fn max<T>(items: Vec<T>) -> UtilsResult<Option<T>>
448 where
449 T: Send + Sync + Clone + Ord + 'static,
450 {
451 if items.is_empty() {
452 return Ok(None);
453 }
454
455 let first = items[0].clone();
456 let result = Self::reduce(items, first, |a, b| if a > b { a } else { b })?;
457 Ok(Some(result))
458 }
459}
460
461#[allow(non_snake_case)]
462#[cfg(test)]
463mod tests {
464 use super::*;
465 use std::sync::atomic::{AtomicUsize, Ordering};
466
467 #[test]
468 fn test_thread_pool_creation() {
469 let pool = ThreadPool::new(4).expect("operation should succeed");
470 assert_eq!(pool.thread_count(), 4);
471 }
472
473 #[test]
474 fn test_thread_pool_execution() {
475 let pool = ThreadPool::new(2).expect("operation should succeed");
476 let counter = Arc::new(AtomicUsize::new(0));
477
478 for _ in 0..10 {
479 let counter_clone = Arc::clone(&counter);
480 pool.execute(move || {
481 counter_clone.fetch_add(1, Ordering::SeqCst);
482 })
483 .expect("operation should succeed");
484 }
485
486 thread::sleep(Duration::from_millis(100));
488
489 assert_eq!(counter.load(Ordering::SeqCst), 10);
490 }
491
492 #[test]
493 fn test_work_stealing_queue() {
494 let queue = WorkStealingQueue::new(4);
495
496 queue.push_local(42).expect("operation should succeed");
497 queue.push_global(24).expect("operation should succeed");
498
499 assert_eq!(
500 queue.get_task().expect("operation should succeed"),
501 Some(42)
502 );
503 assert_eq!(
504 queue.get_task().expect("operation should succeed"),
505 Some(24)
506 );
507 assert_eq!(queue.get_task().expect("operation should succeed"), None);
508 }
509
510 #[test]
511 fn test_parallel_iterator_map() {
512 let items = vec![1, 2, 3, 4, 5];
513 let iter = ParallelIterator::new(items);
514
515 let results = iter.map(|x| x * 2).expect("operation should succeed");
516 assert_eq!(results, vec![2, 4, 6, 8, 10]);
517 }
518
519 #[test]
520 fn test_parallel_iterator_filter() {
521 let items = vec![1, 2, 3, 4, 5, 6];
522 let iter = ParallelIterator::new(items);
523
524 let results = iter
525 .filter(|&x| x % 2 == 0)
526 .expect("operation should succeed");
527 assert_eq!(results, vec![2, 4, 6]);
528 }
529
530 #[test]
531 fn test_parallel_reducer_sum() {
532 let items = vec![1, 2, 3, 4, 5];
533 let result = ParallelReducer::sum(items).expect("operation should succeed");
534 assert_eq!(result, 15);
535 }
536
537 #[test]
538 fn test_parallel_reducer_min_max() {
539 let items = vec![5, 2, 8, 1, 9, 3];
540
541 let min_result = ParallelReducer::min(items.clone()).expect("operation should succeed");
542 assert_eq!(min_result, Some(1));
543
544 let max_result = ParallelReducer::max(items).expect("operation should succeed");
545 assert_eq!(max_result, Some(9));
546 }
547
548 #[test]
549 fn test_parallel_reducer_empty() {
550 let items: Vec<i32> = vec![];
551
552 let min_result = ParallelReducer::min(items.clone()).expect("operation should succeed");
553 assert_eq!(min_result, None);
554
555 let max_result = ParallelReducer::max(items).expect("operation should succeed");
556 assert_eq!(max_result, None);
557 }
558
559 #[test]
560 fn test_thread_pool_with_cpu_cores() {
561 let pool = ThreadPool::with_cpu_cores().expect("operation should succeed");
562 assert!(pool.thread_count() > 0);
563 assert!(pool.thread_count() <= num_cpus::get());
564 }
565}