【问题标题】:Is there a way to parallelize a bash for loop?有没有办法并行化 bash for 循环?
【发布时间】:2015-09-30 05:19:41
【问题描述】:

我有一个简单的脚本,它从一系列硬盘驱动器中提取 SMART 数据并将其写入一个带时间戳的日志文件,该文件稍后会被记录并解析为相关数据。

filename="filename$( date '+%Y_%m_%d_%H%M' ).txt"
for i in {a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p}
do
smartctl -a /dev/sd$i >> /path/to/location/$filename
done 

由于这需要几秒钟才能运行,我想找到一种方法来并行化它。我尝试在循环中的单行末尾附加一个“&”,但这会导致文本文件在部分完成时随意写入,而不是按顺序和以可读的方式写入。有没有办法将其分叉为每个驱动器的单独进程,然后将输出通过管道传输回有序的文本文件?

另外,我假设设置文件名变量必须移动到 for 循环中,以便 fork 能够访问它。但是,如果脚本运行的时间足够长以滚动到新的一分钟(或两分钟),然后脚本变成顺序带日期戳的片段而不是一个连续的文件,则会导致问题。

【问题讨论】:

  • 我假设您可以启动一个新的 bash 并将其置于后台?哦,我明白了,问题出在生成的文件中被乱码。将结果捕获到数组或不同命名的变量中,等待所有子项并在所有操作完成后按所需顺序复制变量。
  • 我不确定你的意思.... 该脚本会在网络连接成功后自动运行,以在远程 ftp 服务器上存档创建的日志文件。
  • 我也试过了(允许每个分叉的进程生成自己的临时文件,然后在归档之前将它们全部连接到一个主文件中)但是实际上运行速度比简单地执行 for 循环慢,因为写入一个驱动器一次。
  • a b c ... 更短且 100% 可移植时,{a,b,c,...} 的意义何在?不要编写 bash 脚本。编写 shell 脚本。
  • @Jens 是的,我确信总会有办法编写更短的脚本,但是问题是关于 bash 中的 for 循环,因为它是已经编写的更大脚本的一部分......等待它... bash。 :D

标签: bash for-loop parallel-processing


【解决方案1】:

像这样使用 GNU Parallel:

parallel -k 'smartctl -a /dev/{}' ::: a b c d e f g h  i j k l m n o p > path/to/output

-k 选项keeps 按顺序输出。如果您想一次运行 8 个,请添加 -j 8,否则每次每个内核运行一个。或者 -j 16 如果你想一次运行它们...

parallel -j 16 -k 'smartctl ....

当然,如果你在bash,你也可以这样做:

parallel -j 16 -k 'smartctl -a /dev/{}' ::: {a..o} > path/to/output

【讨论】:

  • 这是我所希望的。我所做的唯一更改是 /dev/{} 变为 /dev/sd{} 以反映 smartctl 正在寻找的输入,并且我必须安装并行,因为由于某种原因它没有包含在 Ubuntu 14.04 中。并行化 smartctl 实例大大减少了脚本的执行时间。
  • 太棒了!抱歉,我错过了/devsd 部分。很高兴它对你有用。
【解决方案2】:

这样的东西不可行吗? (未测试)

filename="filename$( date '+%Y_%m_%d_%H%M' ).txt"
for i in {a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p}
do
smartctl -a /dev/sd$i > /path/to/location/$filename.$i &
done
wait
cat /path/to/location/$filename.* > /path/to/location/$filename

编辑:看起来最终的猫很慢,那么这个版本呢?

filename="filename$( date '+%Y_%m_%d_%H%M' ).txt"
tmpdir="/dev/shm/tmp$( date '+%Y_%m_%d_%H%M' )"
mkdir $tmpdir
for i in {a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p}
do
smartctl -a /dev/sd$i > $tmpdir/$filename.$i &
done
wait
cat $tmpdir/$filename.* > /path/to/location/$filename
rm -rf $tmpdir

【讨论】:

  • 谢谢,这就是之前的建议,但实际上它的运行速度似乎比原来的 for 循环慢。我希望有一种方法可以并行化它,而不必创建然后 cat 多个文件。
  • 如果这个问题的答案很明显,请原谅,但是使用 tempdir 在将分叉输出连接在一起之前存储分叉输出与在以相同方式连接它们之前将它们存储在本地有很大不同吗?正在运行的系统确实将 tmp 目录安装在 RAM 中,因此理论上这将比旋转盘片 HDD 快得多,但它使用的是 SSD,所以我无法想象会有超过几毫秒的差异?
  • IDK...我只是想让最终的猫更快...但实际上,如果我没看错的话,那就是smartctl 并发出现的多重性会减慢整个过程...因此,首先并行运行它们可能不是一个好主意。也许您可以尝试手动评估可以在不损失性能的情况下并行运行多少个,并通过脚本上的双循环来坚持这个数字,只有内部一个并行化......
  • 我不相信 smartctl 的多次出现是瓶颈。它在 5ghz 标记附近的 8 核机器上运行,并且由于每个硬盘只有一个操作,因此与连续实例相比,并行运行它们似乎会大大减少总体时间。同样,硬盘通过主板上的 SATAIII 插头或 PCI-E 2.0 转接卡成批连接,因此我认为该行的任何地方都不存在带宽瓶颈。
  • smartctl -a 可能非常快。 (我想通过浏览手册页,它只是请求磁盘中已有的信息,实际上并没有触发任何测试。)它可能比实际的磁盘访问快得多,例如当你想写结果文件时。 (尽管有足够的缓存,写入磁盘也应该很快,除非您使用 -o sync 挂载它并使用 hdparm -W0 关闭磁盘缓存,或者您有很多其他 I/O 正在进行)。所以看起来写入磁盘是瓶颈......(ct'd)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多