我试图通过一个简单的示例来理解 shell 脚本中的并行处理,并在输出中确定性地(非随机顺序)按顺序附加值。下面是代码片段:
x=""
appendnum() {
num=$1; x=`echo $x$num`
}
for no in {0..10}
do
appendnum $no &
done
wait $(jobs -rp)
echo $x
预期输出为 012345678910,但结果为空值。我什至尝试迭代 PID 直到它完成,但没有成功。我希望主线程等待每个并行进程完成。附加数字只是一个例子。
我的问题陈述如下:考虑到我有 3 个任务,我想要像这样的响应列表[responseof(task1),responseof(task2),responseof(task3)]
。任务数量最多可以达到 50。无论任务数量多少,我的响应时间都应该相同。最有效和正确的方法是什么?
答案1
如果我理解正确的话,你想要:
- 并行运行任务,即。理想情况下,确保所有这些任务在执行单个任务的时间内完成。 (这不太现实,但我们可以尽力)
- 保持输出的顺序,即使某些较晚的任务先于某些较早的任务完成
考虑到这一点,您可以尝试以下操作:
parallel -k -j10 'sleep {}; echo -n {}' ::: {10..1}
执行的第一个任务花费的时间最长,但由于我们添加了该-k
选项,parallel
实用程序将保持顺序并最终输出
10987654321
如果没有该-k
选项,输出将相反并在命令完成时出现
12345678910
如果您需要更多信息,请查看教程:https://www.gnu.org/software/parallel/parallel_tutorial.html
答案2
你缺少的一些东西:
- Shell 变量存储在 shell 内存中;即shell进程的内存。
- 从 shell 运行的大多数命令都在子进程(或多个进程)中运行。唯一的例外是“内置命令”。
- 异步命令始终在子进程中运行 - 即使它们不运行任何程序。不运行任何程序的异步命令是仅运行 shell 的子进程。这称为“子外壳”。
- 一般来说,进程不能改变其他进程的内存。特别是,子 shell 无法修改主 shell 进程中的变量。所以当你说
appendnum $no &
,appendnum
函数 不能修改x
主shell进程中的变量。
你可以得到类似你想要得到的行为:
x=TR007.out
> "$x"
appendnum() {
echo "$1" >> "$x"
}
for no in {0..10}
do
appendnum $no &
done
wait
您会将数字 0 到 10 写入该文件TR007.out
。
- 异步进程的调度(排序)是不确定的。因此,在上面的示例脚本中,虽然您会将数字 0 到 10 写入文件,但它们可能不按顺序排列。
- 您可能知道,
wait
它本身(不带参数)将等待所有子进程。 - “无论任务数量有多少,我的响应时间都应该是相同的。”这是一个非常大胆的期望/要求。是否合理取决于具体情况。如果该任务是单线程计算密集型任务,并且您有三个或更多(逻辑)CPU,那么,是的,可以合理地预期三个任务并行运行比一个任务本身花费的时间多一点。但如果你有四个逻辑CPU,那就完全没问题了不合理期望在与运行一个任务相同的时间内运行 50 个任务。
- 我提到子(异步)进程按预期顺序运行。由于它们同时运行(即并行),因此它们的执行可能会重叠。所以,如果我们改变上面的脚本来做
附录(){ 回显“$1”a>>“$x” 回声“$1”b>>“$x” } 对于 {1..3} 中的“否” 做 附录 $no & 完毕
那么你可能会在文件中得到///// ——或者你可能1a
会得到///// ,或者你可能会得到///// ,或者更糟。让异步进程写入同一个文件是一个坏主意。1b
2a
2b
3a
3b
2a
2b
1a
1b
3a
3b
2a
1a
2b
3a
3b
1b
你可能应该做类似的事情
对于 {1..3} 中的“否” 做 任务“$no”> 文件“$no”& 完毕 等待 cat 文件1 文件2 文件3 > 组合结果其他注意事项:
$(command)
与 做同样的事情。你应该坚持使用表格。`command`
$(command)
-
说或没有意义。说啊。
x=`echo $x$num`
x=$(echo $x$num)
x="$x$num"
- 您应该始终引用 shell 变量,除非您有充分的理由不这样做,并且您确定您知道自己在做什么。所以不要这样做
appendnum $no
;做appendnum "$no"
等
答案3
[响应(任务1),响应(任务2),响应(任务3)]
parset
是为此而构建的:
parset result responseof ::: task1 task2 task3
echo "${result[1]}"
例如:
parset res seq ::: 3 2 1
echo "${res[1]}"
parset
是 GNU Parallel 的一部分。