I am trying to learn Rust’s Rayon library by making a simple vector addition function. My current code is this, assuming a
, b
and c
are vectors initialized to the same length, c
is mutable and num_threads
is a usize
variable:
let pool = ThreadPoolBuilder::new().num_threads(num_threads).build()
.expect("Could not create thread pool");
pool.install(|| {
(0..c.len()).into_par_iter().for_each(|x| {
c[x] = a[x] + b[x];
});
});
But I get the error error[E0596]: cannot borrow c as mutable, as it is a captured variable in a Fn closure
.
I also want to note that ultimately I aim to make benchmark software, which is why I’m using thread pooling to specify the number of threads, but I think the extra closure pool.install()
uses is part of where the issue is coming from. Modifying the global thread pool also isn’t an option since that can only be done once, and I will want to re-run benchmarks with different thread numbers. I would also like to avoid using scope – if that’s the only solution, so be it – since that would add a performance penalty.
I understand fundamentally what Rayon doesn’t like here: chapter 4.2 of the Rust Book says that you can’t have multiple mutable references to a variable, which is essentially what each thread would be getting. However, aside from the particular question of how I could get this code to work, this raises some other questions.
I can’t seem to even move a reference to c
into the thread pool closure. Why is this a restriction? Surely the power of multithreading is to get multiple threads to concurrently do some work on related data, so why can’t I pass data to the threads this way?
Assuming I could get a reference to c
into the thread pool, would there be some way to make it so that, for instance, thread 0 gets &mut c[0]
, thread 1 gets &mut c[1]
, and so on? If Rayon’s purpose is to abstract some of the boilerplate of Rust’s basic multithreading library, shouldn’t this be something Rayon tries to make simpler?
Some other answers I have seen imply that iterating over the contents of the vectors themselves would help, but since I need all three vectors I would need to use izip. Doing this (replacing (0..c.len().into_par_iter()...
with izip!(&a.mat, &b.mat, &mut c.mat).into_par_iter()...
) gives me the error error[E0599]: the method into_par_iter exists for struct Map<Zip<Zip<Iter<'_, T>, Iter<'_, T>>, IterMut<'_, T>>, {[email protected]:303:9}>, but its trait bounds were not satisfied
, which seems to imply that references are now being moved into the closure. What gives? Why were they not being moved before?
rbriggs is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.