【问题标题】:Why does this variable definition imply static lifetime?为什么这个变量定义意味着静态生命周期?
【发布时间】:2016-10-09 08:43:00
【问题描述】:

我正在尝试对向量块执行函数,然后使用消息传递库将结果发回。

但是,我收到一个关于向量生命周期的奇怪错误,它甚至不参与线程操作:

src/lib.rs:153:27: 154:25 error: borrowed value does not live long enough
src/lib.rs:153   let extended_segments = (segment_size..max_val)
error: src/lib.rs:154     .collect::<Vec<_>>()borrowed value does not live long enough

note: reference must be valid for the static lifetime...:153
  let extended_segments = (segment_size..max_val)
src/lib.rs:153:3: 155:27: 154     .collect::<Vec<_>>()
note: but borrowed value is only valid for the statement at 153:2:
reference must be valid for the static lifetime...
src/lib.rs:
let extended_segments = (segment_size..max_val)
consider using a `let` binding to increase its lifetime

我尝试移动迭代器并将生命周期添加到不同的地方,但我无法让检查器通过并仍然保持输入。

有问题的代码如下,基于concurrency chapter in the Rust book。 (完整代码在github。)

use std::sync::mpsc;
use std::thread;

fn sieve_segment(a: &[usize], b: &[usize]) -> Vec<usize> {
    vec![]
}
fn eratosthenes_sieve(val: usize) -> Vec<usize> {
    vec![]
}

pub fn segmented_sieve_parallel(max_val: usize, mut segment_size: usize) -> Vec<usize> {
    if max_val <= ((2 as i64).pow(16) as usize) {
        // early return if the highest value is small enough (empirical)
        return eratosthenes_sieve(max_val);
    }

    if segment_size > ((max_val as f64).sqrt() as usize) {
        segment_size = (max_val as f64).sqrt() as usize;
        println!("Segment size is larger than √{}. Reducing to {} to keep resource use down.",
                 max_val,
                 segment_size);
    }

    let small_primes = eratosthenes_sieve((max_val as f64).sqrt() as usize);
    let mut big_primes = small_primes.clone();

    let (tx, rx): (mpsc::Sender<Vec<usize>>, mpsc::Receiver<Vec<usize>>) = mpsc::channel();

    let extended_segments = (segment_size..max_val)
        .collect::<Vec<_>>()
        .chunks(segment_size);
    for this_segment in extended_segments.clone() {
        let small_primes = small_primes.clone();
        let tx = tx.clone();

        thread::spawn(move || {
            let sieved_segment = sieve_segment(&small_primes, this_segment);
            tx.send(sieved_segment).unwrap();
        });
    }

    for _ in 1..extended_segments.count() {
        big_primes.extend(&rx.recv().unwrap());
    }

    big_primes
}

fn main() {}

我如何理解和避免这个错误?我不确定如何使线程闭包static as in this question 的生命周期仍然可以重用(即,不是main())。如this question 中所述,我不确定如何“消费所有进入[关闭] 的东西”。而且我不确定在哪里insert .map(|s| s.into()) 以确保所有引用都成为移动,我也不确定我想要。

【问题讨论】:

    标签: multithreading concurrency rust lifetime


    【解决方案1】:

    在尝试重现问题时,我建议您通过删除所有不相关的代码来创建MCVE。在这种情况下,这样的事情似乎会产生同样的错误:

    fn segmented_sieve_parallel(max_val: usize, segment_size: usize) {
        let foo = (segment_size..max_val)
            .collect::<Vec<_>>()
            .chunks(segment_size);
    }
    
    fn main() {}
    

    让我们分解一下:

    1. 在数字之间创建一个迭代器。
    2. 将它们全部收集到Vec&lt;usize&gt;
    3. 返回一个包含对向量的引用的迭代器。
    4. 由于向量没有绑定到任何变量,它在语句的末尾被删除。这将使迭代器指向无效的内存区域,因此这是不允许的。

    查看slice::chunks的定义:

    fn chunks(&self, size: usize) -> Chunks<T>
    
    pub struct Chunks<'a, T> where T: 'a {
        // some fields omitted
    }
    

    生命周期标记'a 让您知道迭代器包含对某事物的引用。 Lifetime elision 已从函数中删除了 'a,如下所示,展开:

    fn chunks<'a>(&'a self, size: usize) -> Chunks<'a, T>
    

    查看这行错误信息:

    帮助:考虑使用let 绑定来延长其生命周期

    您可以按照以下方式进行操作:

    fn segmented_sieve_parallel(max_val: usize, segment_size: usize) {
        let foo = (segment_size..max_val)
            .collect::<Vec<_>>();
        let bar = foo.chunks(segment_size);
    }
    
    fn main() {}
    

    虽然我会把它写成

    fn segmented_sieve_parallel(max_val: usize, segment_size: usize) {
        let foo: Vec<_> = (segment_size..max_val).collect();
        let bar = foo.chunks(segment_size);
    }
    
    fn main() {}
    

    将此代码重新插入到原始问题中不会解决问题,但会更容易理解。那是因为您试图传递对thread::spawn 的引用,这可能比当前线程的寿命更长。因此,传递给thread::spawn 的所有内容都必须具有'static 的生命周期。有大量问题详细说明了为什么必须防止这种情况以及一连串的解决方案,包括作用域线程和克隆向量。

    克隆向量是最简单的,但可能效率低下:

    for this_segment in extended_segments.clone() {
        let this_segment = this_segment.to_vec();
        // ...
    }
    

    【讨论】:

      猜你喜欢
      • 2023-04-11
      • 1970-01-01
      • 2011-09-12
      • 1970-01-01
      • 2016-12-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多