Tokio/Rayon example wrong?

The example is from here and mentioned in the Tokio tutorial:


async fn parallel_sum(nums: Vec<i32>) -> i32 {                                                   
    let (send, recv) = tokio::sync::oneshot::channel();                                          
                                                                                                 
    // Spawn a task on rayon.                                                                    
    rayon::spawn(move || {                                                                       
        // Perform an expensive computation.                                                     
        let mut sum = 0;                                                                         
        for num in nums {                                                                        
            sum += num;                                                                          
        }                                                                                        
                                                                                                 
        // Send the result back to Tokio.                                                        
        let _ = send.send(sum);                                                                  
    });                                                                                          
                                                                                                 
    // Wait for the rayon task.                                                                  
    recv.await.expect("Panic in rayon::spawn")                                                   
}                                                                                                
                                                                                                 
#[tokio::main]                                                                                   
async fn main() { ▶︎ Run |Debug
    let nums = vec![1; 1024 * 1024];
    println!("{}", parallel_sum(nums).await);
}

This yields 1048576 on my box which is wrong IMHO…

karl@rantanplan:~/src/rust/playground/musashi$ cargo run --bin rayon
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.06s
     Running `/home/peter/src/rust/playground/target/debug/rayon`
1048576
karl@rantanplan:~/src/rust/playground/musashi$ perl -E 'say 1024*1024'
1048576

How come? Have I forgotten or overlooked something?

By the way, it is terribly slow.

Ooops, i have overseen the ; - my bad! Sorry!!!

It calculates the sum of 1024*1024 ones, which is 1024*1024 == 1048576. Although I think that the name of the function is misleading, since the sum is not parallel, but sequential, just offloaded to another thread.

1 Like

Run it with the --release cli arg to enable optimizations, that will address why it runs slowly.

The summing is parallel in the sense that rayon splits the large slice into chunks and distributes the workload across multiple threads. Each work item is a sequential for loop, but that's not the interesting part of what the code is doing.

1 Like

But where in this code that happens? rayon::spawn runs passed closure only once (otherwise this wouldn't compile, since this closure uses a oneshot sender and therefore is only FnOnce, not Fn).

1 Like

Sorry for the confusion. I'm not talking about the code in OP. The linked article shows how to use par_iter().

1 Like

Yes, thanks. My embarrassing mistake. I had 1 to 1024 * 1024 in mind for some unknown reason. See my edit above.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.