rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
97.4k stars 12.59k forks source link

Concurrency Example in The Rust Book #34231

Closed nslay closed 7 years ago

nslay commented 8 years ago

First of all, I really appreciate all your work on the language and documentation! I am very eager to use Rust in my work. Now, I come from the numerics side of computation. I have no problem using every single core on the machine and sometimes no problem pushing a GPU either!

But I was both shocked and disappointed by your Concurrency example: https://doc.rust-lang.org/book/concurrency.html

If I understand correctly, this example parallel code is actually a serialized solution in disguise:

use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;

fn main() {
    let data = Arc::new(Mutex::new(vec![1, 2, 3]));

    for i in 0..3 {
        let data = data.clone();
        thread::spawn(move || {
            let mut data = data.lock().unwrap(); // The .lock() usage here is a bad solution and a bad example for readers like me
            data[i] += 1;
        });
    }

    thread::sleep(Duration::from_millis(50));
}

It is less efficient to use this example than to do a simple serial for loop over the array elements. And the Book did indeed mention that no real data race existed in the first place. Assigning elements to an array position unique to a thread is very common in numerical algorithms (e.g. finite difference methods, image processing, etc...).

So, the book leaves me wondering: How do you really solve the above problem without serializing it? Can it be done within the confines of the language's rules? Or do we have to use unsafe { } to insist to the compiler that we really know that no data race exists?

I would suggest update this chapter with a better example. Or at least show a solution where the above algorithm can actually be parallelized without serializing it with a lock.

est31 commented 8 years ago

I think this has been asked here as well: http://stackoverflow.com/questions/31644152

nslay commented 8 years ago

Thanks for sharing that! That's a step in the right direction, but it's not very flexible. What if I want dynamically sized chunks because some array elements require more processing than others?

Have a look at OpenMP. It's a horrible hack on C/C++, but it does make the compiler implement parts of parallel algorithms in a safe way (e.g. safe reduction, safe partitioning of index ranges, safe implicit synchronization). If the language or the compiler have control over how a block of code is parallelized, it may be easier to make safety guarantees in parallel codes without making developers jump through some complicated hoops.

It's also worth noting that my exposure to OpenMP also means that I am biased.

steveklabnik commented 7 years ago

I'm working on the second edition of the book, and it doesn't use any of this text. That also means I'm not working on the first edition of the book.

If someone would like to submit a PR to improve this, please do, but since we're not improving the existing book, we're not keeping issues like this open, so I'm going to give it a close. Thanks!