Reputation: 41
I'm trying to catch the panic from inside par_iter()
and continue to what I have after par_iter
block.
If I have this, I get everything correctly and there's no panic:
let dog: Dog = Dog {
name: "Dog",
vector: vec![1, 2, 3, 4, 5],
};
let cat: Cat = Cat {
name: "Cat",
vector: vec![1, 2, 3],
};
let pig: Pig = Pig {
name: "Pig",
vector: vec![1, 2, 3, 4, 5],
};
let mut v: Vec<Box<dyn Animal>> = Vec::new();
v.push(Box::new(cat));
v.push(Box::new(dog));
v.push(Box::new(pig));
let total = v
.par_iter()
.map(|x| {
println!("{} vector[1] is {:?}", &x.name(), &x.vector()[1]);
x.vector()[1].clone()
})
.collect::<Vec<(i32)>>();
let sum: i32 = total.iter().sum();
println!("sum: {}", sum);
I get the sum after par_iter
Cat vector[1] is 2
Dog vector[1] is 2
Pig vector[1] is 2
sum: 6
When I try to access an index which exceeds the vector length, I still print whatever I have including the panic, but don't get to the sum
:
let total = v
.par_iter()
.map(|x| {
println!("{} vector[4] is {:?}", &x.name(), &x.vector()[4]);
x.vector()[4].clone()
})
.collect::<Vec<(i32)>>();
let sum: i32 = total.iter().sum();
println!("sum: {}", sum);
The result:
Running `target/debug/playground`
thread '<unnamed>' panicked at 'index out of bounds: the len is 3 but the index is 4', /rustc/4560ea788cb760f0a34127156c78e2552949f734/src/libcore/slice/mod.rs:2717:10
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
Standard Output
Dog vector[4] is 5
Pig vector[4] is 5
I tried to to check what I could do if I implemented a panic_handler
:
let panic_handler = move |err: Box<dyn Any + Send>| {
println!("hello");
};
rayon::ThreadPoolBuilder::new()
.num_threads(2)
.panic_handler(panic_handler)
.build_global()
.unwrap();
It doesn't work and it's not even used:
warning: unused variable: `err`
--> src/main.rs:52:31
|
52 | let panic_handler = move |err: Box<dyn Any + Send>| {
| ^^^ help: consider prefixing with an underscore: `_err`
My real problem is not about going out of bounds of the vector, it's about catching the panic from par_iter
if I don't know it will panic or not. My goal is to collect the result and move forward with stuff which didn't panic.
Upvotes: 2
Views: 1184
Reputation: 41
My question was answered in the Rust User's Forum using ::std::panic::catch_unwind()
:
use ::rayon::prelude::*;
trait Animal: Sync + Send {
fn vector(self: &'_ Self) -> Vec<i32>;
fn name(self: &'_ Self) -> String;
}
struct Cat {
name: &'static str,
vector: Vec<i32>,
}
impl Animal for Cat {
fn vector(self: &'_ Self) -> Vec<i32> {
self.vector.clone()
}
fn name(self: &'_ Self) -> String {
self.name.to_string()
}
}
struct Dog {
name: &'static str,
vector: Vec<i32>,
}
impl Animal for Dog {
fn vector(self: &'_ Self) -> Vec<i32> {
self.vector.clone()
}
fn name(self: &'_ Self) -> String {
self.name.to_string()
}
}
struct Pig {
name: &'static str,
vector: Vec<i32>,
}
impl Animal for Pig {
fn vector(self: &'_ Self) -> Vec<i32> {
self.vector.clone()
}
fn name(self: &'_ Self) -> String {
self.name.to_string()
}
}
fn main() {
::rayon::ThreadPoolBuilder::new()
.num_threads(2)
// .panic_handler(move |_: Box<dyn Any + Send>| println!("hello"))
.build_global()
.unwrap();
match ::std::panic::catch_unwind(move || {
let dog: Dog = Dog {
name: "Dog",
vector: vec![1, 2, 3, 4, 5],
};
let cat: Cat = Cat {
name: "Cat",
vector: vec![1, 2, 3],
};
let pig: Pig = Pig {
name: "Pig",
vector: vec![1, 2, 3, 4, 5],
};
let v: Vec<Box<dyn Animal>> = vec![Box::new(cat), Box::new(dog), Box::new(pig)];
let total = v
.par_iter()
.map(|x| {
let vector_4 = x.vector()[4].clone();
println!("{} vector[4] is {:?}", &x.name(), vector_4);
vector_4
})
.collect::<Vec<(i32)>>();
let sum: i32 = total.iter().sum();
println!("sum: {}", sum);
}) {
Ok(()) => (),
Err(err) => {
let err_msg = match (err.downcast_ref(), err.downcast_ref::<String>()) {
(Some(&s), _) => s,
(_, Some(s)) => &**s,
_ => "<No panic message>",
};
eprintln!("Rayon panicked: {}", err_msg);
}
}
println!("This code is always reached");
}
Upvotes: 2
Reputation: 35983
Try using get
(it returns Some(element)
if there is an element at index 4, None
otherwise):
let total = v.par_iter().map(|x| {
println!("{} vector[4] is {:?}", &x.name(), &x.vector().get(4));
x.vector().get(4).map(|x| x.clone())
}).collect::<Vec<Option<i32>>>();
Then, total
will contain Some(n)
where the respective element was present and None
otherwise.
Upvotes: 2