本文目录导读:

在Shell脚本中实现并发执行控制,主要有以下几种常用方法,这里按照从简单到复杂的顺序介绍。
后台运行 + wait(最简单)
这是最基础的并发方式,使用 & 将任务放到后台,然后用 wait 等待所有完成。
#!/bin/bash
# 定义任务函数
task() {
local id=$1
echo "任务 $id 开始"
sleep $((RANDOM % 5 + 1))
echo "任务 $id 结束"
}
# 并发执行多个任务
for i in {1..5}; do
task $i &
done
# 等待所有后台任务完成
wait
echo "所有任务已完成"
优缺点:
- 优点:简单直接
- 缺点:无并发数量限制,可能瞬间启动过多进程导致系统负载过高
信号量控制(限制并发数)
使用 mkfifo 创建命名管道实现信号量,控制同时运行的进程数量。
#!/bin/bash
# 并发控制函数 - 使用命名管道作为信号量
concurrent_control() {
local max_concurrent=$1 # 最大并发数
local task_file=$2 # 任务列表文件
# 创建临时FIFO(命名管道)作为信号量
local fifo_file=$(mktemp -u)
mkfifo $fifo_file
exec 3<>$fifo_file
rm -f $fifo_file
# 初始化信号量:向管道写入max_concurrent个令牌
for ((i=0; i<$max_concurrent; i++)); do
echo >&3
done
# 读取任务并执行
while IFS= read -r task; do
# 从管道读取令牌(无令牌时会阻塞)
read -u 3
# 启动任务
(
echo "执行任务: $task"
eval "$task" # 实际执行任务
echo "任务完成: $task"
# 任务结束后归还令牌
echo >&3
) &
done < "$task_file"
# 等待所有任务完成
wait
# 清理
exec 3>&-
}
# 使用示例
cat > /tmp/tasks.txt << EOF
sleep 2; echo "任务1"
sleep 3; echo "任务2"
sleep 1; echo "任务3"
sleep 4; echo "任务4"
sleep 2; echo "任务5"
sleep 3; echo "任务6"
EOF
# 限制最多同时运行3个任务
concurrent_control 3 /tmp/tasks.txt
xargs 实现并发控制(最推荐)
xargs 的 -P 参数可以非常方便地控制并发数。
#!/bin/bash
# 定义要执行的任务
task() {
local id=$1
echo "任务 $id 开始 (PID: $$)"
sleep $((RANDOM % 5 + 2))
echo "任务 $id 结束"
}
# 导出函数,使xargs可以访问
export -f task
# 生成任务参数列表
seq 1 10 | xargs -I {} -P 5 bash -c 'task "$@"' _ {}
echo "所有任务完成"
更实用的示例:
#!/bin/bash
# 批量下载文件,最多3个并发
download_file() {
local url=$1
local filename=$(basename $url)
echo "开始下载: $filename"
wget -q $url -O /tmp/$filename
echo "下载完成: $filename"
}
export -f download_file
# 从文件读取URL列表,并发3个下载
cat urls.txt | xargs -I {} -P 3 bash -c 'download_file "$@"' _ {}
GNU parallel(功能最强大)
如果系统安装了 parallel 命令,这是处理并发任务的最佳选择。
#!/bin/bash
# 安装GNU parallel(如果未安装)
# Ubuntu/Debian: apt-get install parallel
# CentOS/RHEL: yum install parallel
# 基本使用
task() {
local id=$1
echo "任务 $id"
sleep 2
echo "任务 $id 完成"
}
export -f task
# 并发5个任务
parallel -j 5 task ::: {1..20}
# 从文件读取参数
parallel -j 3 -a params.txt task
# 在处理命令时保留输出顺序
parallel --keep-order -j 4 task ::: {1..12}
GNU parallel的高级特性:
#!/bin/bash
# 分布式执行
parallel --sshlogin server1,server2 -j 2 task ::: {1..10}
# 错误处理
parallel --halt now,fail=1 -j 3 task ::: {1..10}
# 进度显示
parallel --progress -j 4 task ::: {1..100}
# 结果保存
parallel --results output/ -j 4 task ::: {1..10}
完整的生产环境示例
结合了多种技术的实际应用:
#!/bin/bash
# 生产环境的并发任务管理器
set -euo pipefail
# 配置
MAX_CONCURRENT=4
LOG_DIR="/var/log/concurrent_tasks"
PID_FILE="/tmp/concurrent_tasks.pid"
# 日志函数
log() {
local level=$1
local msg=$2
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$level] $msg"
}
# 任务函数
process_item() {
local item=$1
local task_id=$2
log "INFO" "【任务$task_id】开始处理: $item"
# 模拟处理时间
sleep $((RANDOM % 5 + 2))
# 模拟失败情况
if [ $((RANDOM % 10)) -eq 0 ]; then
log "ERROR" "【任务$task_id】处理失败: $item"
return 1
fi
log "INFO" "【任务$task_id】处理成功: $item"
}
# 主函数
main() {
local task_list=("数据A" "数据B" "数据C" "数据D" "数据E" "数据F" "数据G")
local total=${#task_list[@]}
local success_count=0
local fail_count=0
# 创建日志目录
mkdir -p "$LOG_DIR"
log "INFO" "开始并发处理 $total 个任务,最大并发数: $MAX_CONCURRENT"
# 导出函数和变量
export -f process_item log
export LOG_DIR
# 使用xargs控制并发
for i in "${!task_list[@]}"; do
echo "${task_list[$i]} $i"
done | xargs -n 2 -P $MAX_CONCURRENT bash -c 'process_item "$1" "$2"' _
log "INFO" "所有任务处理完成"
}
main "$@"
选择建议
- 简单场景(并发数少,不敏感):使用
&+wait - 需要控制并发数:使用
xargs -P或命名管道 - 复杂场景(错误处理、分布式):使用
GNU parallel - 脚本可移植性重要:使用命名管道方式
建议:对于大多数生产环境,xargs -P 是最平衡的选择——既简单又功能完整。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播