Multithreading Rust中带多线程的并行字计数
我想计算一个大字符串中单词的频率 简单的单线程解决方案如下所示Multithreading Rust中带多线程的并行字计数,multithreading,rust,Multithreading,Rust,我想计算一个大字符串中单词的频率 简单的单线程解决方案如下所示 use hashbrown::HashMap; fn main() { let buffer = String::from("Hello World Hello Rust"); let mut frequency: HashMap<&str, u32> = HashMap::new(); for word in buffer.split_whitespace() { *
use hashbrown::HashMap;
fn main() {
let buffer = String::from("Hello World Hello Rust");
let mut frequency: HashMap<&str, u32> = HashMap::new();
for word in buffer.split_whitespace() {
*frequency.entry(word).or_insert(0) += 1;
}
}
为了简化代码,我删除了字符串分块,并且在for循环中只生成了1个线程。作用域线程允许您借用线程外部的内容,并在线程内部使用它。他们不能允许你做相反的事情,从线里面借东西,让它逃走 split_whitespace借用buffer,buffer已移动到内部闭包中,因此属于当前线程。每个字都是一个引用,其生存期依赖于缓冲区,当线程退出时,缓冲区将超出范围。底层字符串不会被销毁,但word只能从Arc借用,因为Arc的生存期较短。如果你只是克隆了一个字符串,同样的事情也会发生 圆弧螺纹和作用域螺纹有些不一致。Arc用于在线程之间共享某个对象,并且希望在最后一个线程退出时销毁该对象。您通常不知道或不关心哪个线程是破坏它的线程,只知道它被破坏了。另一方面,当您确实知道应该销毁某个对象的位置时,就会使用作用域线程,所有希望访问该对象的线程都必须在销毁之前退出。由于使用作用域线程静态验证生命期,因此可以使用普通&引用而不是Arc。这适用于字符串和互斥体 让我们应用这个:
let buffer = String::from("Hello World Hello Rust");
let frequency: Mutex<HashMap<&str, u32>> = Mutex::new(HashMap::new());
crossbeam::scope(|scope| {
for _ in 0..1 {
scope.spawn(|_| {
for word in buffer.split_whitespace() {
let mut frequency = frequency.lock().unwrap();
*frequency.entry(word).or_insert(0) += 1;
}
});
}
});
哦,那很容易。注意,并没有移动,并没有弧,也并没有克隆,频率将包含对缓冲区的引用,这大概是你们想要的。为了使这一点起作用,您使用的任何字符串组块方法都必须借用原始str;每个线程不能有单独的字符串
警告
我不确定您的示例与原始代码到底有多相似。上述解决方案解决了编译问题,但正如Shepmaster所指出的:
我要补充的是,最初的算法不是很有效,因为HashMap的争用量将达到极限。对于每个线程来说,拥有自己的HashMap并在最后合并它们可能会更有效。[……] 另见
如果您使用的是横梁,为什么您的输入字符串呈弧形?为什么要特意使用hashbrown?这里的问题是并行化根本帮不了你,因为线程需要独占地拥有字符串。不能同时对同一字符串上的多个线程进行操作。你必须事先把它分开。你的例子没有得到很好的考虑。我要补充的是,最初的算法不是很有效,因为HashMap的争用量将是极端的。对于每个线程来说,拥有自己的HashMap并在最后合并它们可能会更有效。另见
let buffer = String::from("Hello World Hello Rust");
let frequency: Mutex<HashMap<&str, u32>> = Mutex::new(HashMap::new());
crossbeam::scope(|scope| {
for _ in 0..1 {
scope.spawn(|_| {
for word in buffer.split_whitespace() {
let mut frequency = frequency.lock().unwrap();
*frequency.entry(word).or_insert(0) += 1;
}
});
}
});