并行多个文件的 bash 脚本

asp*_*e57 4 parallel-processing bash

我读过有关该主题的类似问题,但没有一个可以帮助我解决以下问题:

我有一个 bash 脚本,如下所示:

#!/bin/bash

for filename  in /home/user/Desktop/emak/*.fa; do
    mkdir ${filename%.*}
    cd ${filename%.*}
    mkdir emak
    cd ..
done
Run Code Online (Sandbox Code Playgroud)

该脚本基本上执行以下操作:

  • 遍历目录中的所有文件
  • 使用每个文件的名称创建一个新目录
  • 进入新文件并创建一个名为“emak”的新文件

真正的任务执行比创建“emak”文件更昂贵的计算......

我有大约数千个文件需要迭代。由于每次迭代都独立于前一次迭代,因此我希望将其拆分到不同的处理器(我有 24 个核心)中,这样我就可以同时处理多个文件。

我读过一些关于并行运行的文章(使用:GNU),但我没有看到在这种情况下应用它的明确方法。

谢谢

che*_*ner 7

不需要parallel;你可以简单地使用

N=10
for filename in /home/user/Desktop/emak/*.fa; do
    mkdir -p "${filename%.*}/emak" &
    (( ++count % N == 0)) && wait
done
Run Code Online (Sandbox Code Playgroud)

第二行暂停每个第 N 个作业,以便在继续之前完成所有先前的作业。


Mar*_*ell 5

GNU Parallel 与此类似,您可以创建并导出一个名为 的 bash 函数doit

#!/bin/bash

doit() {
    dir=${1%.*}
    mkdir "$dir"
    cd "$dir"
    mkdir emak
}
export -f doit
parallel doit ::: /home/user/Desktop/emak/*.fa
Run Code Online (Sandbox Code Playgroud)

如果“计算成本高”部分所花费的时间较长,或者特别可变,您将真正看到这种方法的好处。如果需要的时间(例如最多 10 秒)且可变,GNU Parallel 将在 N 个并行进程中最短的一个完成后立即提交下一个作业,而不是等待所有 N 个作业完成后再开始下一批 N 个作业。

作为粗略基准,这需要 58 秒:

#!/bin/bash

doit() {
   echo $1
   # Sleep up to 10 seconds
   sleep $((RANDOM*11/32768))
}
export -f doit
parallel -j 10 doit ::: {0..99}
Run Code Online (Sandbox Code Playgroud)

这是直接比较的,需要 87 秒:

#!/bin/bash
N=10
for i in {0..99}; do
    echo $i
    sleep $((RANDOM*11/32768)) &
    (( ++count % N == 0)) && wait
done
Run Code Online (Sandbox Code Playgroud)