Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
585 views
in Technique[技术] by (71.8m points)

multithreading - Channels for passing hashmap between threads | stuck in loop | Rust

I am solving a problem for the website Exercism in rust, where I basically try to concurrently count how many times different letters occur in some text. I am doing this by passing hashmaps between threads, and somehow am in some kind of infinite loop. I think the issue is in my handling of the receiver, but I really don't know. Please help.

use std::collections::HashMap;
use std::thread;
use std::sync::mpsc;
use std::str;

pub fn frequency(input: &[&str], worker_count: usize) -> HashMap<char, usize> {
   
   // Empty case 
   if input.is_empty() {
       return HashMap::new();
   }

   // Flatten input, set workload for each thread, create hashmap to catch results
   let mut flat_input = input.join("");
   let workload = input.len() / worker_count;
   let mut final_map: HashMap<char, usize> = HashMap::new();

   
   let (tx, rx) = mpsc::channel();
   for _i in 0..worker_count {
       let task = flat_input.split_off(flat_input.len() - workload);
       let tx_clone = mpsc::Sender::clone(&tx);

       
       // Separate threads ---------------------------------------------
       thread::spawn(move || {
          let mut partial_map: HashMap<char, usize> = HashMap::new();
          for letter in task.chars() {
              match partial_map.remove(&letter) {
                  Some(count) => {
                      partial_map.insert(letter, count + 1);
                  },
                  None => {
                      partial_map.insert(letter, 1);
                  }
              }
          }
          tx_clone.send(partial_map).expect("Didn't work fool");
       });
       // --------------------------------------------------  
       
   }
   
   // iterate through the returned hashmaps to update the final map
   for received in rx {
       for (key, value) in received {
           match final_map.remove(&key) {
               Some(count) => {
                   final_map.insert(key, count + value);
               },
               None => {
                   final_map.insert(key, value);
               }  
           }
       }
   }
   
   return final_map;
}
question from:https://stackoverflow.com/questions/65649189/channels-for-passing-hashmap-between-threads-stuck-in-loop-rust

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Iterating on the receiver rx will block for new messages while senders exist. The ones you've cloned into the threads will drop out of scope when they're done, but you have the original sender tx still in scope.

You can force tx out of scope by dropping it manually:

for _i in 0..worker_count {
    ...
}

std::mem::drop(tx); // <--------

for received in rx {
    ...
}


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...