我如何从Rayon的`par_iter()`引起恐慌?

时间:2019-11-28 14:42:14

标签: rust panic rayon

我正试图从par_iter()内部捕捉恐慌,并继续执行par_iter封锁后的工作。

如果我有这个,我会正确地获得一切,而不会出现恐慌:

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);

我在par_iter之后得到总和

Cat vector[1] is 2
Dog vector[1] is 2
Pig vector[1] is 2
sum: 6

当我尝试访问超出向量长度的索引时,我仍然会打印出包括恐慌在内的所有内容,但不要进入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);

结果:

     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

我尝试检查如果实施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();

它不起作用,甚至没有被使用:

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`

playground

我真正的问题不在于超越向量的界限,而是关于par_iter中的恐慌,如果我不知道它是否会恐慌。我的目标是收集结果并继续处理不会引起恐慌的内容。

2 个答案:

答案 0 :(得分:1)

尝试使用get(如果索引4处有元素,则返回Some(element)None则返回):

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>>>();

然后,total将包含存在相应元素的Some(n),否则将包含None

答案 1 :(得分:1)

我的问题是使用::std::panic::catch_unwind()的{​​{3}}:

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");
}