Hi, I just started to learn Rust. For my toy project I've picked to write a linear algebra library. I would like to run some computations in parallel but I've ran into some troubles.
- Will different threads run on different cores or on one? In other words, just using threads will I have true parallelism or just a concurrency?
- My code doesn't compile. I've made a toy snippet just for this post that aims to compute an inner product of two vectors but with a separate thread for every term in the product.
use std::sync::{Arc, Mutex};
use std::thread;
struct Vector {
_data: Arc<Mutex<Vec<f64>>>,
pub m: usize,
}
impl Vector {
fn new(d: Vec<f64>) -> Vector {
let m = d.len();
Vector {
_data: Arc::new(Mutex::new(d)),
m: m,
}
}
fn inner(&self, v: &Vector) -> f64 {
assert!(self.m == v.m);
let mut val = 0.;
let val_ref = Arc::new(Mutex::new(&val));
let mut threads = vec![];
for i in 0..self.m {
let u_data = self._data.clone();
let v_data = v._data.clone();
let val_inner = val_ref.clone();
threads.push(thread::spawn(move || {
let u_loc = u_data.lock().unwrap();
let v_loc = v_data.lock().unwrap();
let mut val_loc = val_inner.lock().unwrap();
**val_loc += u_loc[i] * v_loc[i];
}));
}
for thread in threads {
thread.join().unwrap();
}
val
}
}
fn main() {
let v = Vector::new(vec![1., 2.]);
let u = Vector::new(vec![-2., 2.]);
assert_eq!(u.inner(&v), 2.);
}
I get the following compile error:
error[E0594]: cannot assign to data in a dereference of `std::sync::MutexGuard<'_, &f64>`
--> src/main.rs:32:17
|
32 | **val_loc += u_loc[i] * v_loc[i];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot assign
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::sync::MutexGuard<'_, &f64>`
warning: variable does not need to be mutable
--> src/main.rs:20:13
|
20 | let mut val = 0.;
| ----^^^
| |
| help: remove this `mut`
|
= note: `#[warn(unused_mut)]` on by default
error[E0597]: `val` does not live long enough
--> src/main.rs:21:43
|
21 | let val_ref = Arc::new(Mutex::new(&val));
| -----------^^^^-
| | |
| | borrowed value does not live long enough
| argument requires that `val` is borrowed for `'static`
...
39 | }
| - `val` dropped here while still borrowed
error: aborting due to 2 previous errors
What is the right and idiomatic way to do this? Also why does the code compile, when I remove the return variable, i.e when every thread computes the product of two numbers and just drops it. I would expect the compiler complain about the lifetimes of the vectors. Does it use the "handle.join()" block to realize that the self and v object outlive the threads?