使用GNU parallel来并行化Bash for循环

3
我有一个for循环,它在100个不同的输入文件夹上运行Python脚本约100次。 Python脚本在2个核心上效率最高,我有50个可用核心。因此,我想使用GNU并行处理程序一次在25个文件夹上运行脚本。
这是我的for循环(当然是顺序的),Python脚本需要一堆输入变量,包括-p 2,它在两个核心上运行:
for folder in $(find /home/rob/PartitionFinder/ -maxdepth 2 -type d); do
        python script.py --raxml --quick --no-ml-tree $folder --force -p 2
done

这是我尝试进行并行化的代码,但它没有起作用:

folders=$(find /home/rob/PartitionFinder/ -maxdepth 2 -type d)

echo $folders | parallel -P 25 python script.py --raxml --quick --no-ml-tree {} --force -p 2

我遇到的问题(也许只是众多问题中的第一个)是我的folders变量不是一个列表,因此实际上它只是将 100 个文件夹作为{}字符串传递给脚本。
非常感谢任何提示。
3个回答

6

echo $folders | parallel ... 替换为 echo "$folders" | parallel ...

如果没有双引号,shell 会解析 $folders 中的空格,并将它们作为单独的参数传递给 echo,导致它们在一行上打印。 parallel 将每一行作为作业的参数提供。

为了完全避免这种引用问题,将 find 直接管道到 parallel,并使用 null 字符作为分隔符,总是一个好主意:

find ... -print0 | parallel -0 ...

这将适用于包含多个空格或换行符的文件名。

哎呀!两个简单的解决方案。我本来想不到第一个,但应该试试第二个。谢谢。 - roblanf

4
你可以直接将find命令的输出作为parallel命令的输入:
 find /home/rob/PartitionFinder/ -maxdepth 2 -type d | parallel -P 25 python script.py --raxml --quick --no-ml-tree {} --force -p 2

如果您想保留 $folder 中的字符串,您可以将 echo 命令输出的结果通过管道传递给 xargs 命令。
echo $folders | xargs -n 1 | parallel -P 25 python script.py --raxml --quick --no-ml-tree {} --force -p 2

0
你可以像这样创建一个Makefile:
#!/usr/bin/make -f

FOLDERS=$(shell find /home/rob/PartitionFinder/ -maxdepth 2 -type d)

all: ${FOLDERS}

# To execute the find before the all
find_folders:
    @ echo $(FOLDERS) > /dev/null

${FOLDERS}: find_folders
    @ python script.py --raxml --quick --no-ml-tree $@ --force -p 2

然后运行make -j 25

注意:在文件中使用制表符进行缩进

此外,名称中有空格的文件将无法工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接