DEV Community

Billy Chan
Billy Chan

Posted on

Multi-thread Processing in Rust

Most program we wrote is single threaded. Since most of the task is IO bound. It make sense to keep it simple by writing a single threaded program. But what if we have a CPU bound task? Let say, cracking a MD5 hash? Don't ask me why cracking MD5 hash, it's just one of CPU intensive task that I can think of, purely for demo purpose.

A naive hashing algorithm will be like this.

// Iterate from 0 util we found the target number
let mut i = 0_u32;
loop {
    // Hash our guessing number and compare with the target hash
    // Stop the loop if we found the target number
    if md5::compute(i.to_string()).eq(&TARGET_HASH) {
        break;
    }
    // What's our next guess?
    i += 1;
}
Enter fullscreen mode Exit fullscreen mode

For the hashing task we can distribute the work to N threads. With each thread start search the target number starting from N and continue the search by incrementing the number by N.

So, for example we've 3 threads. The search space for each thread would be:

Thread 1: 1, 4, 7, 10...
Thread 2: 2, 5, 8, 11...
Thread 3: 3, 6, 9, 12...
Enter fullscreen mode Exit fullscreen mode

That's how we divide the task to N threads with each thread work on a unique and non-overlapping search space.

// A MPSC channel to inform the main thread some worker found the solution
let (tx, rx) = mpsc::channel();
print!("Parallel hashing with {} threads: ", num_workers);

// Spawn workers
for worker in 0..num_workers {
    // Clone the transmission end and move it into the spawned worker
    let tx1 = tx.clone();
    thread::spawn(move || {
        // The guess number start from the worker number
        let mut i = worker;
        // Iterate from 0 util we found the target number
        loop {
            // Hash our guessing number and compare with the target hash
            let hash = md5::compute(i.to_string());
            // Stop the loop if we found the target number
            // And inform the main thread that we found the target number
            if hash.eq(&TARGET_HASH) {
                tx1.send("Found!").unwrap();
                break;
            }
            // What's our next guess?
            i += num_workers;
        }
    });
}

while let Ok(_) = rx.recv() {
    // Exit main thread, this will kill all spawn threads
    break;
}
Enter fullscreen mode Exit fullscreen mode

Source code available on GitHub.

Top comments (0)