我想并行化一个 for 循环,其中循环中的迭代次数可能非常大,例如 10^6。因此,如果我可以创建线程而不是进程,那就更好了。怎么做?代码如下
N=$1
for (( i=0; i < $N; i++ )); do
./random >> output /* in each iteration one random number is appended to
a file "output" */
done
答案1
- 您无法从 shell 中生成线程。
- 您不想从多个进程写入同一个文件。
- 如果你的
random
程序只是生成一个数字,- 它应该足够快,以便您的循环将受到 io 限制。
- 如果可以的话,您应该编辑它以接受参数并打印那么多数字。
- 如果实际执行是瓶颈,您应该重新考虑如何生成数字。也许将代码发布到代码审查。
如果你真的真的还是想这样做,分块做:
for i in {0..9}; do
for ((j = 1; j < $N/10; j++)); do
./random
done > tmp$i &
pid[$i]=$?
done
for i in {0..9}; do
wait ${pid[$i]}
done
cat tmp{0..9} >> outfile
答案2
我不知道有任何 shell 允许您手动创建新线程,通常您只能利用当前 shell 中的现有线程(或创建子 shell,它们实际上是新进程)。使用python
或其他语言代替。
即使可以,我也真的不建议使用 shell 脚本来完成这种规模的事情。与编译语言相比,运行 10^6 次迭代时性能损失可能很大。
答案3
一如既往,问题是资源争用。您需要限制同时运行的进程/线程的数量。
此外,是否拥有并发线程很大程度上取决于将执行的处理类型。如果有一个良好的编程组合:内存、cpu、i/o 等,那就更好了。如果所有子进程都将执行所有 cpu 操作,那么同时运行 10-20 个子进程不会加快任何速度。您可以尝试将处理工作外包给其他机器;例如,使用 ssh 在其他机器上启动调用并获取结果。
快速而肮脏的第一遍可能是这样的:
N=$1 # max number to iterate on
shift # rest of command line is the command to run: e.g. "./random"
maxcount=10 # maximum in the pool
curcount=0 # how many currently in the pool
reaper () {
wait
curcount=`expr $curcount - 1`
}
spawnnext () {
n=$1
shift
while [ $curcount -ge $maxcount ]; do
sleep 1 # wait for a free slot in the pool
done
echo $n
"$@" &
curcount=`expr $curcount + 1`
}
trap 'reaper' CHLD
for (( i=0; i < $N; i++)); do
spawnnext $i "$@"
done
笔记;我还没有测试过这个;只是临时写下来的。
但我会用更高级、性能更好的语言(例如 Python)来完成此操作:https://stackoverflow.com/questions/3033952/python-thread-pool-similar-to-the-multiprocessing-pool
答案4
如果您的任务只是生成随机数:
perl -e 'for($t=0;$t<1000000;$t++) { print int(rand()*1000),"\n" }'
如果您的任务确实是其他任务,您可以使用 GNU Parallel:
parallel ./random :::: <(seq 1000000) > output
您可以简单地通过以下方式安装 GNU Parallel:
wget http://git.savannah.gnu.org/cgit/parallel.git/plain/src/parallel
chmod 755 parallel
观看介绍视频以了解更多信息:http://pi.dk/1