Bet*_*moo 218 parallel-processing bash
我正在尝试编写一个同时运行许多程序的.sh文件
我试过这个
prog1
prog2
Run Code Online (Sandbox Code Playgroud)
但是运行prog1然后等到prog1结束然后开始prog2 ...
那我怎么能并行运行呢?
Ory*_*and 279
怎么样:
prog1 & prog2 && fg
Run Code Online (Sandbox Code Playgroud)
这将:
prog1
.prog2
,并将其保持在前台,以便您可以将其关闭ctrl-c
.prog2
,你会回到prog1
的前景,所以你也可以关闭它ctrl-c
.psm*_*ars 190
prog1 &
prog2 &
Run Code Online (Sandbox Code Playgroud)
Ole*_*nge 61
使用GNU Parallel http://www.gnu.org/software/parallel/,它很简单:
(echo prog1; echo prog2) | parallel
Run Code Online (Sandbox Code Playgroud)
或者如果您愿意:
parallel ::: prog1 prog2
Run Code Online (Sandbox Code Playgroud)
学到更多:
tru*_*ktr 61
你可以使用wait
:
some_command &
P1=$!
other_command &
P2=$!
wait $P1 $P2
Run Code Online (Sandbox Code Playgroud)
它将后台程序PID分配给变量($!
是最后一个启动的进程'PID),然后wait
命令等待它们.这很好,因为如果你杀死脚本,它也会杀死进程!
Qui*_*ant 33
如果你想能够轻松地运行并杀死多个进程ctrl-c
,这是我最喜欢的方法:在(…)
子shell中生成多个后台进程,并SIGINT
执行trap kill 0
,这将杀死子shell组中生成的所有内容:
(trap 'kill 0' SIGINT; prog1 & prog2 & prog3)
Run Code Online (Sandbox Code Playgroud)
你可以有复杂的流程执行结构,一切都将关闭单ctrl-c
(只需确保最后的过程是在前台运行,即没有一个包括&
后prog1.3
):
(trap 'kill 0' SIGINT; prog1.1 && prog1.2 & (prog2.1 | prog2.2 || prog2.3) & prog1.3)
Run Code Online (Sandbox Code Playgroud)
#!/bin/bash
prog1 & 2> .errorprog1.log; prog2 & 2> .errorprog2.log
Run Code Online (Sandbox Code Playgroud)
将错误重定向到单独的日志.
这对我来说效果很好(在这里找到):
sh -c 'command1 & command2 & command3 & wait'
Run Code Online (Sandbox Code Playgroud)
它输出混合的每个命令的所有日志(这就是我想要的),并且所有日志都用 ctrl+c 杀死。
有一个非常有用的程序叫nohup.
nohup - run a command immune to hangups, with output to a non-tty
Run Code Online (Sandbox Code Playgroud)
xargs -P <n>
允许您<n>
并行运行命令。
尽管这-P
是一个非标准选项,但GNU(Linux)和macOS / BSD实施均支持该选项。
下面的例子:
time xargs -P 3 -I {} sh -c 'eval "$1"' - {} <<'EOF'
sleep 1; echo 1
sleep 2; echo 2
sleep 3; echo 3
echo 4
EOF
Run Code Online (Sandbox Code Playgroud)
输出看起来像:
1 # output from 1st command
4 # output from *last* command, which started as soon as the count dropped below 3
2 # output from 2nd command
3 # output from 3rd command
real 0m3.012s
user 0m0.011s
sys 0m0.008s
Run Code Online (Sandbox Code Playgroud)
时间显示命令是并行运行的(最后一个命令仅在原始3个命令中的第一个终止后才启动,但执行速度非常快)。
在xargs
所有命令完成之前,命令本身不会返回,但是您可以在后台执行该操作&
,方法是使用控制操作符终止该命令,然后使用wait
内置函数等待整个xargs
命令完成。
{
xargs -P 3 -I {} sh -c 'eval "$1"' - {} <<'EOF'
sleep 1; echo 1
sleep 2; echo 2
sleep 3; echo 3
echo 4
EOF
} &
# Script execution continues here while `xargs` is running
# in the background.
echo "Waiting for commands to finish..."
# Wait for `xargs` to finish, via special variable $!, which contains
# the PID of the most recently started background process.
wait $!
Run Code Online (Sandbox Code Playgroud)
注意:
BSD / MacOS的xargs
要求指定命令的计数并行运行明确,而GNU xargs
允许你指定-P 0
要尽可能多的运行尽可能平行。
并行运行的进程的输出在生成时会到达,因此将无法预料地交错。
parallel
如Ole的回答中所述(大多数平台都不标准),GNU可以方便地在每个进程的基础上对输出进行序列化(分组),并提供更多高级功能。我最近有类似的情况,我需要同时运行多个程序,将它们的输出重定向到分离的日志文件并等待它们完成,我最终得到类似的东西:
#!/bin/bash
# Add the full path processes to run to the array
PROCESSES_TO_RUN=("/home/joao/Code/test/prog_1/prog1" \
"/home/joao/Code/test/prog_2/prog2")
# You can keep adding processes to the array...
for i in ${PROCESSES_TO_RUN[@]}; do
${i%/*}/./${i##*/} > ${i}.log 2>&1 &
# ${i%/*} -> Get folder name until the /
# ${i##*/} -> Get the filename after the /
done
# Wait for the processes to finish
wait
Run Code Online (Sandbox Code Playgroud)
资料来源:http://joaoperibeiro.com/execute-multiple-programs-and-redirect-their-outputs-linux/
这是我使用的函数,以便并行运行max n进程(在示例中n = 4):
max_children=4
function parallel {
local time1=$(date +"%H:%M:%S")
local time2=""
# for the sake of the example, I'm using $2 as a description, you may be interested in other description
echo "starting $2 ($time1)..."
"$@" && time2=$(date +"%H:%M:%S") && echo "finishing $2 ($time1 -- $time2)..." &
local my_pid=$$
local children=$(ps -eo ppid | grep -w $my_pid | wc -w)
children=$((children-1))
if [[ $children -ge $max_children ]]; then
wait -n
fi
}
parallel sleep 5
parallel sleep 6
parallel sleep 7
parallel sleep 8
parallel sleep 9
wait
Run Code Online (Sandbox Code Playgroud)
如果将max_children设置为内核数,则此函数将尝试避免空闲内核.