【问题标题】:Is there a way to get threads to not compete as hard for I/O resources?有没有办法让线程不那么激烈地争夺 I/O 资源?
【发布时间】:2021-05-11 10:21:19
【问题描述】:

我编写了以下并行测试用例,它的运行速度至少比 md5sum 二进制文件慢 2 倍:

// dependencies are md-5 = "0.9.1", rayon = "1.5.0", hex-slice = "0.1.4"

use std::{
    convert::TryInto,
    env::args_os,
    fs::File,
    io::{Error, Read},
    path::PathBuf,
};

use hex_slice::AsHex;
use md5::{self, digest::Digest};
use rayon::prelude::*;

fn main() {
    args_os()
        .skip(1)
        .collect::<Vec<_>>()
        .par_iter()
        .for_each(|path| {
            println!(
                "{:02x}  {}",
                md5sum(PathBuf::from(&path)).unwrap().plain_hex(false),
                path.to_string_lossy()
            );
        });
}

fn md5sum(path: PathBuf) -> Result<[u8; 16], Error> {
    let mut file = File::open(path)?;
    let mut ctx = md5::Md5::default();
    let mut buf = vec![0u8; 2_097_152];
    loop {
        let bytes_read = file.read(&mut buf)?;
        if bytes_read == 0 {
            break;
        }
        ctx.update(&buf[0..bytes_read]);
    }
    Ok(ctx.finalize().try_into().unwrap())
}

如果我删除并行性(将par_iter() 更改为iter()),它会比md5sum 二进制文件快一点,所以编译器和md-5 板条箱肯定不是问题。该算法并非完全受 I/O 限制,因为两个 md5sum 进程比一个进程处理两个文件要快一些。

测试背景:我在测试之间通过使用 SysInternals RamMap 清空工作集和备用列表来刷新磁盘缓存。其他背景:我在 WSL2 中运行代码,但在 Windows 文件夹中校验和文件。数据位于传统硬盘驱动器上。

我尝试了 ThreadPool,使用 tokio 进行异步读取(与信号量并行+并发以确保没有打开太多文件)和 Rayon(如上所述)。我尝试了从 512 KB 到 10 MB 的缓冲区大小。操作系统或驱动器控制器应该足够智能以尽可能快地读取数据,但它无法正常工作,可能是因为系统想要设置延迟的下限。有什么方法可以通过并发读取获得不错的性能?

【问题讨论】:

    标签: rust concurrency parallel-processing


    【解决方案1】:

    不是一个完整的解决方案:我通过使用Semaphore(不是互斥体,因为我希望在 SSD 上允许多次读取)来限制 I/O,从而获得了一些加速。我重新安排了代码以与计算分开进行读取,但这不适合非常大的文件。

    读取将是顺序的,但计算可以并行发生:

    fn md5sum(io_lock: Arc<Semaphore>, path: PathBuf) -> Result<[u8; 16], Error> {
        let buf = {
            let _lock = io_lock.access();
            let mut file = File::open(path)?;
            let mut buf = Vec::new();
            file.read_to_end(&mut buf)?;
            buf
        };
        Ok(md5::Md5::digest(&buf).try_into().unwrap())
    }
    

    如果有办法让操作系统优化读取,还是很高兴的。

    【讨论】:

      猜你喜欢
      • 2022-01-16
      • 2020-08-17
      • 1970-01-01
      • 1970-01-01
      • 2019-06-26
      • 2011-05-09
      • 2020-10-23
      • 1970-01-01
      • 2015-06-01
      相关资源
      最近更新 更多