2

I have an array of strings. I would like to count the total chars but using threads for parallelisation (the original problem is not this but is similar).

use std::thread;

pub fn frequency<'a>(input: &'a [&'a str], worker_count: usize) -> usize {
    let handlers: Vec<thread::JoinHandle<usize>> = input
        .chunks(worker_count)
        .map(|chunk| thread::spawn(calculate(chunk)))
        .collect();

    let hashes = handlers.into_iter().map(|handler| handler.join().unwrap());

    let mut sum = 0;
    for h in hashes {
        sum += h
    }

    sum
}

fn calculate<'a>(input: &'a [&'a str]) -> impl Fn() -> usize + 'a {
    move || input.iter().map(|s| s.len()).sum()
}

The compiler tells me this:

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
 --> src/lib.rs:5:10
  |
5 |         .chunks(worker_count)
  |          ^^^^^^
  |
note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 3:18...
 --> src/lib.rs:3:18
  |
3 | pub fn frequency<'a>(input: &'a [&'a str], worker_count: usize) -> usize {
  |                  ^^
note: ...so that reference does not outlive borrowed content
 --> src/lib.rs:4:52
  |
4 |     let handlers: Vec<thread::JoinHandle<usize>> = input
  |                                                    ^^^^^
  = note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `impl std::ops::Fn<()>` will meet its required lifetime bounds
 --> src/lib.rs:6:22
  |
6 |         .map(|chunk| thread::spawn(calculate(chunk)))
  |                      ^^^^^^^^^^^^^

I've tried to remove all lifetimes, use different lifetimes for str and the slice, and explicitly invoke calculate::<'a> but none of those solutions compile.

The input lifetime is the same everywhere: frequency declares 'a that is used in calculate, so the closure is bound to 'a because the captured variables live for 'a.

Where am I wrong?

NB: I would like not to use 'static.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
allevo
  • 844
  • 1
  • 9
  • 20
  • `calculate` looks fine, but `thread::spawn` explicitly requires `'static` because spawned threads may outlive the original. – trent Dec 09 '19 at 22:50
  • 1
    You're probably looking for [How can I pass a reference to a stack variable to a thread?](https://stackoverflow.com/questions/32750829/how-can-i-pass-a-reference-to-a-stack-variable-to-a-thread) Does that answer your question? – trent Dec 09 '19 at 22:52
  • It looks like your question might be answered by the answers of [How can I sum up using concurrency from 1 to 1000000 with Rust?](https://stackoverflow.com/q/44624591/155423); [How can I pass a reference to a stack variable to a thread?](https://stackoverflow.com/q/32750829/155423). If not, please **[edit]** your question to explain the differences. Otherwise, we can mark this question as already answered. – Shepmaster Dec 09 '19 at 23:41
  • 1
    [Here's an translation using `crossbeam`, as in the other question](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=c03aee8e742d95d3704f4f549f5d7e8f), but it's probably not a typical use of scoped threads. [Here's one I'd consider more readable](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=67a52bf43a9d993d80d6a3289becdaa1). YMMV. – trent Dec 10 '19 at 01:00
  • The code in the question (and both versions I just posted) has a bug: the argument to `chunks` is the size of each chunk, not the number of chunks. You probably intended something like `input.chunks((input.len() + worker_count - 1)/worker_count)`. – trent Dec 10 '19 at 01:08

0 Answers0