我有一个使用 gnu 并行的脚本。我想为每个“迭代”传递两个参数
在串行运行中我有类似的东西:
for (( i=0; i<=10; i++ ))
do
a = tmp1[$i]
b = tmp2[$i]
done
我想将其平行化为
func pf()
{
a=$1
b=$2
}
export -f pf
parallel --jobs 5 --linebuffer pf ::: <what to write here?>
答案1
省略其他parallel
标志只是为了保持专注......
parallel --link pf ::: A B ::: C D
这将首先使用 运行您的函数a=A
,b=C
然后运行a=B
,b=D
或
a=A b=C
a=B b=D
如果没有--link
你得到像这样的完整组合:
a=A b=C
a=A b=D
a=B b=C
a=B b=D
更新:正如 Ole Tange 在评论中提到的那样 [已删除 -埃德。] 还有另一种方法可以做到这一点:使用:::+
运算符。然而,这两种选择之间有一个重要的区别如果每个参数位置的参数数量不相同。举个例子来说明。
parallel --link pf ::: A B ::: C D E
输出:
a=A b=C
a=B b=D
a=A b=E
parallel pf ::: A B :::+ C D E
输出:
a=A b=C
a=B b=D
因此,--link
将“包装”以便消耗所有参数,同时:::+
将忽略额外的参数。 (在一般情况下,我更喜欢,--link
因为替代方案在某种意义上是默默地忽略输入。YMMV。)
答案2
为了简化,我将假设 bash 并且数组从 1 而不是从 0 开始索引。想要做这样的事情似乎很直观:
parallel ... pf '$tmp1[{#}]' '$tmp2[{#}]' ::: $(seq 10)
其中函数的两个参数pf
是命令的一部分,我们使用并行表示法{#}
来代表作业编号(对于 10 个作业,设置为 1 到 10。我们只需seq
在 后面获取 10 个参数,:::
以确保我们执行 10 项作业(未使用 seq 值,只是恰好与作业编号相同。)
不幸的是,这不起作用,因为 bash 不导出数组变量。但它可以导出函数,并且手册页显示了使用简单函数导出/导入您选择的函数的parallel
解决方法,这将设置您选择的数组变量:import_array
my_importer
declare -a tmp1 tmp2
for (( i=1; i<=10; i++ ))
do tmp1[$i]=x$i
tmp2[$i]=y$i
done
import_array(){
local func=$1; shift;
export $func='() {
'"$(for arr in $@; do
declare -p $arr|sed '1s/declare -./&g/'
done)"'
}'
}
import_array my_importer tmp1 tmp2
我们只需要告诉parallel
将my_importer
函数传递到命令的环境中pf
,并使用 option --env my_importer
,然后在运行之前运行该函数pf
:
pf(){ a=$1; b=$2; echo "job a=$a b=$b"; }
export -f pf
parallel -v --jobs 5 --linebuffer \
--env my_importer 'my_importer;' pf '${tmp1[{#}]}' '${tmp2[{#}]}' ::: $(seq 10)
结果输出-v
类似于
my_importer; pf ${tmp1[2]} ${tmp2[2]}
my_importer; pf ${tmp1[1]} ${tmp2[1]}
my_importer; pf ${tmp1[5]} ${tmp2[5]}
my_importer; pf ${tmp1[3]} ${tmp2[3]}
job a=x1 b=y1
my_importer; pf ${tmp1[6]} ${tmp2[6]}
job a=x2 b=y2
my_importer; pf ${tmp1[7]} ${tmp2[7]}
job a=x4 b=y4
...