【发布时间】:2019-06-22 19:39:17
【问题描述】:
我有一个 Bash 脚本,其中有一个循环,其中有一个 Bash 命令调用另一个 Bash 脚本,而后者又调用 Python 脚本。
循环中的每个 bash 命令都可以彼此独立运行。当我稍后在实际数据集上运行它时,执行每个命令需要一些时间。因此,我想利用并并行化这部分脚本。
我花了几天时间研究了 Bash 中执行并行执行的选项,同时还让我可以选择我想要并行化代码的内核数量,这样我就不会淹没服务器。在寻找 GNU 选项后,xargs -P 在我看来是最合理的,因为我不必拥有特定的 Bash 版本,并且无需安装额外的库即可工作。但是,即使它看起来很简单,我也很难让它发挥作用。
#!/bin/bash
while getopts i:t: option
do
case "${option}"
in
i) in_f=${OPTARG};;
t) n_threads=${OPTARG};;
esac
done
START=$(date +%s)
class_file=$in_f
classes=( $(awk '{print $1}' ./$class_file))
rm -r tree_matches.txt
n="${#classes[@]}"
for i in $(seq 0 $n);
do
for j in $(seq $((i+1)) $((n-1)));
do
echo ${classes[i]}" "${classes[j]} >> tree_matches.txt
done
done
col1=( $(awk '{print $1}' ./tree_matches.txt ))
col2=( $(awk '{print $2}' ./tree_matches.txt ))
printf "%s\0" {0..1275} | xargs -0 -I k -P $n_threads sh myFunction.sh -1 ${classes[k]} -2 ${classes[k]}
n_pairs="${#col1[@]}"
END=$(date +%s)
DIFF=$(( $END - $START ))
echo "Exec time $DIFF seconds"
您可以忽略最初的两个嵌套循环,为了完整起见,我只是粘贴了整个脚本。将要并行化的部分是从脚本末尾算起的第 4 行代码:
printf "%s\0" {0..1275} | xargs -0 -I k -P $n_threads sh myFunction.sh -1 ${classes[k]} -2 ${classes[k]}
这将遍历所有对,在我的例子中总共为 1275 个,并且理想情况下将使用变量 $n_threads 与指定数量的线程并行执行 myFunction.sh。
但是,我做错了,因为该行中的迭代器 k 没有索引我的两个数组 ${classes[k]} 和 ${classes[k]}。
循环不断迭代 1275 次,但当我回显它们时,它只索引两个数组的第一个元素。我后来将该行更改为此行以进行故障排除:
printf "%s\0" {0..1275} | xargs -0 -I k -P $n_threads echo "index" k
实际上每次循环时都会增加k 的值,但是当我将该行更改为:
printf "%s\0" {0..1275} | xargs -0 -I k -P $n_threads echo "index" "$((k))"
它打印了 0, 1275 次作为 k 的值。我不知道我做错了什么。
我实际上有两个大小相同的向量,它们是myFunction.sh 脚本的输入。我只想要一个整数索引能够同时索引它们并使用从这两个向量索引的这两个值调用我的函数。根据您的建议,我将代码修改如下:
for x in {0..10};
do
printf "%d\0" "$x"; done| xargs -0 -I @@ -P $n_threads sh markerGenes2TreeMatch.sh -1 ${col1[@@]}-2 ${col2[@@]}
但是现在当我执行代码时出现以下错误:
@@: syntax error: operand expected (error token is "@@")
我猜这个索引@@ 仍然是字符串格式。我只希望在循环时生成整数索引,并且可以并行执行此命令。
【问题讨论】:
-
我不确定为什么你的最后一个命令不起作用,但请注意
-I暗示-L 1,即如果一次只处理一行输入。 -
k只能增加xargs如果它看到它!${classes[k]}被初始脚本扩展 -
对,我认为问题在于评估的顺序。
$(( ... ))在xargs看到它之前由shell 处理,这就是为什么$(( {} ))(或任何你用作-I的参数)不起作用的原因。您可能必须在您的xargs命令中使用bash -c,请参阅the manual。
标签: bash parallel-processing xargs gnu-parallel