rust:跨多个线程使用 hashmap arc 和 rwlock

Ces*_*esc 2 rust

试图解决如何从不同线程将内容插入到 hasmap 的问题,但仍然无法得到它。

为什么以下程序在每次执行时都会缺少一些键?我目前的理解是.write等待获取锁并.join等待所有线程完成?

因此,我希望最终所有线程都将它们的值插入到哈希图中,但显然我仍然缺少一些东西。

操场

use std::collections::HashMap;
use std::sync::Arc;
use std::sync::RwLock;
use std::thread;
use std::vec;

pub fn main() {
    let mut contacts: HashMap<String, String> = HashMap::new();
    contacts.insert("main-thread".to_owned(), "hello world".to_owned());

    let contacts = Arc::new(RwLock::new(contacts));
    let mut children = vec![];
    for _ in 0..10 {
        let lock_contacts = Arc::clone(&contacts);
        children.push(thread::spawn(move || {
            let num = thread::current().id();
            let num = format!("{num:?}");
            if let Ok(mut contacts) = lock_contacts.write() {
                contacts.insert(num.clone(), "hey".to_owned());
            }
        }));
    }
    let _ = children.into_iter().map(|c| c.join());
    dbg!(contacts);
}
Run Code Online (Sandbox Code Playgroud)

Ale*_*uze 7

在退出主线程之前,您实际上并没有加入线程。而你的罪魁祸首就是这一行。

let _ = children.into_iter().map(|c| c.join());
Run Code Online (Sandbox Code Playgroud)

这条线什么也不做。没有迭代,这是因为 Rust 中的迭代器是惰性的。如果您不丢弃从地图返回的值,您将收到以下警告。

warning: unused `Map` that must be used
  --> src/main.rs:23:5
   |
23 |     children.into_iter().map(|c| c.join());
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: iterators are lazy and do nothing unless consumed
   = note: `#[warn(unused_must_use)]` on by default
help: use `let _ = ...` to ignore the resulting value
   |
23 |     let _ = children.into_iter().map(|c| c.join());
   |     +++++++
Run Code Online (Sandbox Code Playgroud)

请注意这部分:迭代器是惰性的,除非被消耗,否则什么都不做

解决方案不是忽略此警告,而是迭代这些值并实际加入线程。您可以通过使用使用迭代器适配器(例如Iterator::for_each )来完成此操作:

warning: unused `Map` that must be used
  --> src/main.rs:23:5
   |
23 |     children.into_iter().map(|c| c.join());
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: iterators are lazy and do nothing unless consumed
   = note: `#[warn(unused_must_use)]` on by default
help: use `let _ = ...` to ignore the resulting value
   |
23 |     let _ = children.into_iter().map(|c| c.join());
   |     +++++++
Run Code Online (Sandbox Code Playgroud)

或者简单地使用for循环:

children.into_iter().for_each(|c| c.join().unwrap());
Run Code Online (Sandbox Code Playgroud)