【问题标题】:Bash: parallelize md5sum checksum on many filesBash:在许多文件上并行化 md5sum 校验和
【发布时间】:2013-05-22 06:02:36
【问题描述】:

假设我有一个 64 核服务器,我需要计算 /mnt/data 中所有文件的 md5sum,并将结果存储在文本文件中:

find /mnt/data -type f -exec md5sum {} \; > md5.txt

上述命令的问题是,在任何给定时间只有一个进程运行。我想利用我的 64 核的全部功能。理想情况下,我想确保在任何给定时间,64 个并行 md5 进程正在运行(但不超过 64 个)。

还有。我需要将所有进程的输出存储到一个文件中。

注意:我不是在寻找一种方法来并行计算一个文件的md5sum。我正在寻找一种方法来并行计算 64 个不同文件的 64 个 md5sum,只要有来自 find 的任何文件。

【问题讨论】:

  • 我不确定这会不会好。我可以想象这些东西很快就会受到 IO 限制,并且使用 64 个进程会导致 IO 变慢,而许多内核仍然处于空闲状态。
  • 但另一方面,现代文件系统大量缓存在 RAM 中,因此一次使用多个文件系统是有意义的。
  • @Alfe:内核仍然需要将数据放入 RAM,所以瓶颈仍然存在。
  • 我对一个笼统的答案很感兴趣。如果 md5sum 对您来说太快(cca 90MB/s),那么可以随意替换任何慢速算法(xz 压缩 5MB/s)。假设 /mnt/data 的读取速度可以达到 500MB/s(即 NFS 共享超过 10Gb 网络或 SSD 磁盘)并非不现实
  • 如果 OP 想要一个并行运行的解决方案,为什么有人开始谈论“错误的想法”?也许他只是想测试 I/O 瓶颈或其他什么...根本不了解那些 什么都知道 用户... (urbandictionary.com/…)

标签: bash


【解决方案1】:

您也可以使用 xargs,它可能比某些发行版上的并行更可用。

-P 控制产生的进程数。

find /mnt/data -type f | xargs -L1 -P24  md5sum > /tmp/result.txt

【讨论】:

  • 只要文件名包含空格,提供的答案似乎就不起作用。正确的是以下一个,也使用 POSIX 开关:“ find /mnt/data -type f -print0 | xargs -L1 -P24 -0 md5 > /tmp/result.txt ”您可能还想使用选项 - r 用于 md5 反转输出并在路径之前获取校验和,以便您可以按校验和排序并轻松找到重复项。
  • @Braiam 它仍然不适用于包含空格的文件名。那些特别需要“-print0”和“-0”来拆分输出,而不是根据空格(可能在文件名中)而是根据空字符。
  • @OlafM 是的,我说的是折旧的标志。我想在功能上保持相同的答案。 find 的行为在标志被贬值之前会出现这个问题。
  • 现在这个答案得到了如此多的关注:让我们从另一个已删除的答案中恢复评论:“这将失败!同时从多个流写入一个文件将生成损坏的文件(!)。请执行不使用它。我的情况确实有问题。- 2014 年 3 月 21 日 6:49"
  • 您可能会发现在 -L 上使用较大的值可以通过分叉更少的进程来提高性能(md5sum 可以在其命令行上获取多个文件)。顺便说一句,如果多个进程都使用附加模式和合理的缓冲方案(例如行缓冲),则它们可以写入同一个(本地)文件。不知道 md5[sum] 是否是这样一个过程。或者写入多个文件并在最后合并。
【解决方案2】:

更新

如果你不想使用额外的包你可以试试 sg 像这样:

#!/usr/bin/bash

max=5;
cpid=()

# Enable job control to receive SIGCHLD
set -m
remove() {
  for i in ${!cpid[*]}; do
    [ ! -d /proc/$i ] && echo UNSET $i && unset cpid[$i] && break
  done
}
trap remove SIGCHLD

for x in $(find ./ -type f -name '*.sh'); do
  some_long_process $x&
  cpid[$!]="$x";
  while [ ${#cpid[*]} -ge $max ]; do
    echo DO SOMETHING && sleep 1;
  done
done
wait

如果子进程退出,它首先允许接收 SIGCHLD。如果是 SIGCHLD,它会找到第一个不存在的进程并从 cpid 数组中删除。

在 for 循环中,它以异步方式启动 max 数量的 some_long_process 进程。 max 到达它会轮询添加到 cpid 数组的所有 pid。它一直等到cpid 的长度小于max,然后异步启动更多进程。

如果列表结束,则等待所有子项完成。

添加

终于找到了合适的解决方案here

【讨论】:

  • 感谢脚本。不幸的是,它并没有带来任何改进。确实,时间比简单的查找要长。此外,大多数内核似乎都处于空闲状态。如果可以的话,我将不得不进行试验。
  • @user1968963:也许sleep 1 行可以被删除。它将不必要地加载一个核心。试试这样。也许您可以使用find /mnt/data -type f -exec md5sum {} + > md5.txt 改进一点。注意尾随+ 而不是;!这将减少调用md5sum 的次数。 (参见find(1) 中的-exec command {} +)。
【解决方案3】:

如果您想进行实验,请尝试安装 md5deep。 (http://md5deep.sourceforge.net)

Here is the manual你可以在这里阅读:

-jnn 控制多线程。默认情况下,程序将创建一个生产者线程来扫描文件系统和每个 CPU 一个哈希线程 核。多线程导致输出文件名在 非确定性顺序,因为需要较长时间进行散列的文件将是 在散列时延迟。如果需要确定性顺序, 指定 -j0 禁用多线程

如果这没有帮助,则说明您遇到了 I/O 瓶颈。

【讨论】:

    【解决方案4】:

    使用GNU parallel。您可以找到更多关于如何实现它的示例here

    find /mnt/data -type f | parallel -j 64 md5sum > md5.txt
    

    【讨论】:

    • 我不知道 GNU 并行。谢谢你提到它。不过,我将不得不看看它是否对我有用。目前,time find /mnt/data -type f | parallel -j 16 md5sum > md5.txt 比正常查找 time find /usr/share -type f -exec md5sum {} \; > md5.txt 慢约 3 倍。
    • -j 64 的问题是它仍然为每个文件分叉一个 md5sum 进程;加上并行本身的开销。试试 -X 而不是 -j 64,这对我有用。如果它适合您,请编辑答案。
    猜你喜欢
    • 2011-07-20
    • 2015-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多