我试图考虑如何从不同的线程将东西插入到hasmap中,但仍然无法实现.

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

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

playground

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);
}

推荐答案

在从Main退出之前,您实际上并没有加入线程.而你的罪魁祸首就是这条线.

let _ = children.into_iter().map(|c| c.join());

这是does nothing号线.没有迭代,这是因为Ruust中的迭代器是lazy.如果您不丢弃从映射返回的值,您将收到以下警告.

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());
   |     +++++++

请注意这一部分:iterators are lazy and do nothing unless consumed.

解决方案不是忽略这个警告,而是迭代这些值并实际联接线程.您可以通过使用像Iterator::for_each这样的迭代器适配器来实现:

children.into_iter().for_each(|c| c.join().unwrap());

或者简单地使用一个for循环:

for child in children {
    child.join().unwrap()
}

Rust相关问答推荐

rust 蚀将动力特性浇到混凝土 struct 上是行不通的

为什么我需要在这个代码示例中使用&

是否提供Bundle 在可执行文件中的warp中的静态文件?

Const 上下文:从 init 函数创建具有 const 通用长度的数组

要求类型参数有特定的大小?

带引脚和不带引脚的比较功能

tokio::spawn 有和没有异步块

返回优化后的标题:返回异步块的闭包的类型擦除

没有明确地说return会产生错误:match arms have incompatible types

按下 Ctrl + C 时优雅地停止命令并退出进程

了解 Rust 闭包:为什么它们持续持有可变引用?

Rust/Serde/HTTP:序列化`Option`

为什么传递 option.as_ref 的行为不同于使用匹配块并将内部映射到 ref 自己?

当我不满足特征界限时会发生什么?

Rust 中的let是做什么的?

Rustlings 切片原语

如何为返回正确类型的枚举实现 get 方法?

如果我立即等待,为什么 `tokio::spawn` 需要一个 `'static` 生命周期?

如果返回类型是通用的,我可以返回 &str 输入的一部分吗?

为什么 Rust 标准库同时为 Thing 和 &Thing 实现特征?