#thread-pool #thread #pool #worker-thread #threading #parallelism

lending_thread_pool

A thread pool where workers can lend their data to their tasks

2 releases

new 0.1.1 Nov 15, 2024
0.1.0 Nov 14, 2024

#526 in Concurrency

Download history 175/week @ 2024-11-10

175 downloads per month

MIT license

14KB
185 lines

lending thread pool

Documentation Crates.io Build status

A thread pool where workers can lend their data to their tasks.

This library implements an admittedly simple thread pool with a peculiar feature: workers can hold on to some data and lend it to their tasks, thus greatly simplifying lifetimes in some scenarios, e.g. when you want to show the status of each thread (idle/running).

Usage

Here is a basic example:

use std::{thread::sleep, time::Duration};
use lending_thread_pool::ThreadPool;

let cores = 4;

let mut pool = ThreadPool::new(
	(0..cores)
		.map(|i| format!("Hello from worker {i}"))
		.collect::<Vec<_>>(),
);

for _ in 0..cores {
	pool.enqueue(move |worker_greetings| {
		println!("Message from worker: {worker_greetings}");
		sleep(Duration::from_millis(100));
	});
}

As you might notice, ThreadPool::new doesn't take a number, but rather a Vec, which can contain anything. The number of threads in the pool will correspond to the length of the provided Vec.

Each item in the Vec will be moved to the corresponding thread. This way, when a worker gets assigned a task, it will be able to temporarily lend its data, through a mutable reference, to the task closure.

This lending mechanism makes it possible for tasks to share information. A common scenario where you might want to take advantage of this feature is showing some progress bars, for example, using indicatif we can do something like this:

use indicatif::{MultiProgress, ProgressBar};
use std::{thread::sleep, time::Duration};
use lending_thread_pool::ThreadPool;

// Assuming we have 4 cores
let cores = 4;
// Simulating 16 expensive things to do in parallel
let tasks = 16;

let multi_pb = MultiProgress::new();

let main_pb = multi_pb.add(ProgressBar::new(tasks));

// Initialize a thread pool where workers own their
// respective indicatif progress bars.
let mut pool = ThreadPool::new(
	(0..cores)
		.map(|_| multi_pb.add(ProgressBar::new(10)))
		.collect::<Vec<_>>(),
);

for _ in 0..tasks {
	// Simulate a long operation on the main thread
	sleep(Duration::from_millis(100));

	// We can now recycle the worker progress bar for each task
	pool.enqueue(move |progress_bar| {
		// Simulate a series of long operations on the worker thread
		for _ in 0..10 {
			sleep(Duration::from_millis(10));
			progress_bar.inc(1);
		}
		progress_bar.reset();
	});
	main_pb.inc(1);
}

For complete examples, you can explore the project examples directory.

Dependencies

~7MB
~114K SLoC