如何并行运行Shell函数的多个实例并等待全部执行完成?
问题
我有如下Shell脚本:
#!/bin/bash myfunc() { #do something (call a rest service) sleep 300 status=$(get status of the operation performed above) while [ "$status" != "succeeded" ]; do #do something (call a rest service) sleep 300 status=$(get status of the operation performed above) done } a=0 while [ $a -lt 1000 ] do a=`expr $a + 1` myfunc done
在最优情况下,上述脚本至少需要5×1000=5000秒才能执行完成。请问是否有办法让myfunc的调用并行化,使while循环可以生成多个myfunc的运行实例?
注意:脚本必须等待所有myfunc实例执行完成后再结束。
解决方案
当然可以!在bash里实现并行化最直接的方式就是把每个myfunc的调用放到后台运行(用&符号),然后用wait命令等待所有后台进程完成。这样所有myfunc实例会同时启动,总耗时就接近单个myfunc的执行时间(最优下5分钟),而不是串行的5000秒。
基础并行实现版本
修改你的脚本,把myfunc调用改成后台运行,同时记录进程ID,最后统一等待:
#!/bin/bash myfunc() { #do something (call a rest service) sleep 300 status=$(get status of the operation performed above) while [ "$status" != "succeeded" ]; do #do something (call a rest service) sleep 300 status=$(get status of the operation performed above) done } # 存储后台进程ID的数组 pids=() a=0 while [ $a -lt 1000 ] do a=$((a + 1)) # 用更现代的bash算术写法替代expr myfunc & # 让myfunc在后台运行 pids+=($!) # 记录当前后台进程的ID done # 等待所有后台进程执行完成 wait "${pids[@]}" echo "所有myfunc实例已执行完成!"
进阶:控制并发数(避免资源耗尽)
一次性启动1000个并发进程可能会消耗大量系统资源(比如网络连接、进程数),如果你的REST服务有并发限制,或者系统资源有限,建议控制同时运行的进程数,比如每次只启动20个,等一批完成再启动下一批:
#!/bin/bash myfunc() { #do something (call a rest service) sleep 300 status=$(get status of the operation performed above) while [ "$status" != "succeeded" ]; do #do something (call a rest service) sleep 300 status=$(get status of the operation performed above) done } max_concurrent=20 # 设置最大并发数 pids=() a=0 while [ $a -lt 1000 ] do a=$((a + 1)) myfunc & pids+=($!) # 当进程数达到最大并发数时,等待任意一个后台进程完成再继续 if [ ${#pids[@]} -ge $max_concurrent ]; then wait -n # 等待任意一个后台进程结束 # 移除已完成的进程ID(可选,保持数组整洁) pids=("${pids[@]/$!/}") fi done # 等待剩余的所有进程完成 wait "${pids[@]}" echo "所有myfunc实例已执行完成!"
这个版本既保留了并行执行的效率,又避免了一次性启动过多进程导致的资源耗尽问题。
内容的提问来源于stack exchange,提问作者Vajira Prabuddhaka
相关产品推荐
相关产品推荐

