用于在bash中运行并行子进程的bash脚本的奇怪行为

时间:2011-09-22 16:01:07

标签: bash parallel-processing

以下脚本用于在bash中运行并行子进程,该进程与Running a limited number of child processes in parallel in bash?

略有不同
#!/bin/bash
set -o monitor # means: run background processes in a separate processes...
N=1000
todo_array=($(seq 0 $((N-1))))
max_jobs=5
trap add_next_job CHLD
index=0
function add_next_job {
    if [[ $index -lt ${#todo_array[@]} ]]
    then
    do_job $index &
    index=$(($index+1))
    fi
}
function do_job {
    echo $1 start
    time=$(echo "scale=0;x=$RANDOM % 10;scale=5;x/20+0.05" |bc);sleep $time;echo $time
    echo $1 done
}
while [[ $index -lt $max_jobs ]] && [[ $index -lt ${#todo_array[@]} ]]
do
    add_next_job
done
wait

这项工作是选择一个0.05:0.05:5.00的随机数,然后再睡几秒钟。

例如,当N = 10时,输出样本

1 start
4 start
3 start
2 start
0 start
.25000
2 done
5 start
.30000
3 done
6 start
.35000
0 done
7 start
.40000
1 done
8 start
.40000
4 done
9 start
.05000
7 done
.20000
5 done
.25000
9 done
.45000
6 done
.50000
8 done

共有30行。

但对于像1000这样的大N,结果可能很奇怪。一次运行产生2996行输出,998行开始,999完成,999带浮点数.644和652在开始时丢失,644完成了。

这些测试在Arch Linux上使用bash 4.2.10(2)运行。使用bash 4.1.5(1)可以在debian stable上生成类似的结果。

编辑:我在moreutils和GNU parallel中尝试并行进行此测试。在moreutils中并行有同样的问题。但GNU并行工作完美。

2 个答案:

答案 0 :(得分:1)

我唯一能想到的就是你的资源不足;检查“ulimit -a”并查找“最大用户进程”。如果这比您想要产生的进程数少,那么最终会出错。

尝试将用户的限制(如果您没有以root身份运行)设置为更高的限制。在Redhatish系统上,您可以通过以下方式执行此操作:

将该行添加到/etc/pam.d/login:

session required pam_limits.so

将以下内容添加到/etc/security/limits.conf:

myuser soft nproc 1000
myuser hard nproc 1024

其中“myuser”是被授予权限的用户名,1000是“max user processes”的默认值,1024是userprocesses的最大数量。软限制和硬限制不应该分开太多。它只说明了允许用户在shell中使用“ulimit”命令设置自己的内容 因此,myuser将以总共1000个进程(包括shell,所有其他生成的进程)开始,但可以使用ulimit将其提升到1024:

$ ulimit -u
1000
$ ulimit -u 1024
$ ulimit -u
1024
$ ulimit -u 2000
-bash: ulimit: max user processes: cannot modify limit: Operation not permitted

不需要重启,它可以立即生效。

祝你好运! 亚历克斯。

答案 1 :(得分:1)

我认为这只是因为所有子进程都继承了相同的文件描述符并试图并行追加到它。很少有两个进程竞争,并且都开始在同一位置附加,一个覆盖另一个。这基本上与其中一条评论所暗示的相反。

您可以通过管道重定向来轻松检查这一点,例如使用your_script | tee file,因为管道具有关于小于特定大小的单write()次调用所传递数据的原子性的规则。

关于SO的另一个问题与此类似(我认为它只涉及两个线程都快速写数字),这也解释了但是我找不到它。