str*_*lan 9 parallel-processing bash for-loop
我有一个类似于以下的bash脚本:
NUM_PROCS=$1
NUM_ITERS=$2
for ((i=0; i<$NUM_ITERS; i++)); do
python foo.py $i arg2 &
done
Run Code Online (Sandbox Code Playgroud)
将并行进程数限制为NUM_PROCS的最简单方法是什么?我正在寻找一种不需要包/安装/模块(如GNU Parallel)的解决方案.
当我尝试Charles Duffy的最新方法时,我从bash -x得到以下错误:
+ python run.py args 1
+ python run.py ... 3
+ python run.py ... 4
+ python run.py ... 2
+ read -r line
+ python run.py ... 1
+ read -r line
+ python run.py ... 4
+ read -r line
+ python run.py ... 2
+ read -r line
+ python run.py ... 3
+ read -r line
+ python run.py ... 0
+ read -r line
Run Code Online (Sandbox Code Playgroud)
...继续使用介于0和5之间的其他数字,直到启动了太多进程来处理系统并关闭bash脚本.
GNU、macOS/OSX、FreeBSD 和 NetBSD 都可以做到这一点xargs -P
,无需 bash 版本或软件包安装。一次有 4 个进程:
printf "%s\0" {1..10} | xargs -0 -I @ -P 4 python foo.py @ arg2
Run Code Online (Sandbox Code Playgroud)
作为一个非常简单的实现,取决于bash的新版本足够新wait -n
(等待只有下一个作业退出,而不是等待所有作业):
#!/bin/bash
# ^^^^ - NOT /bin/sh!
num_procs=$1
num_iters=$2
declare -A pids=( )
for ((i=0; i<num_iters; i++)); do
while (( ${#pids[@]} >= num_procs )); do
wait -n
for pid in "${!pids[@]}"; do
kill -0 "$pid" &>/dev/null || unset "${pids[$pid]}"
done
done
python foo.py "$i" arg2 & pids["$!"]=1
done
Run Code Online (Sandbox Code Playgroud)
如果在没有shell的情况下运行wait -n
,可以(非常低效地)用命令替换它,例如sleep 0.2
,每隔1/5秒轮询一次.
由于您实际上是从文件中读取输入,因此另一种方法是启动N个子进程,每个进程只在以下位置进行(linenum % N == threadnum)
:
num_procs=$1
infile=$2
for ((i=0; i<num_procs; i++)); do
(
while read -r line; do
echo "Thread $i: processing $line"
done < <(awk -v num_procs="$num_procs" -v i="$i" \
'NR % num_procs == i { print }' <"$infile")
) &
done
wait # wait for all $num_procs subprocesses to finish
Run Code Online (Sandbox Code Playgroud)
bash
4.4将有一个有趣的新型参数扩展,简化了Charles Duffy的答案.
#!/bin/bash
num_procs=$1
num_iters=$2
num_jobs="\j" # The prompt escape for number of jobs currently running
for ((i=0; i<num_iters; i++)); do
while (( ${num_jobs@P} >= num_procs )); do
wait -n
done
python foo.py "$i" arg2 &
done
Run Code Online (Sandbox Code Playgroud)