备忘一个脚本.
又一篇写shell多进程的blog,之前整理过一篇,现在整理的,算是将“常见事务”封装一下,以便可以随时拿来使用。最常见的“多进程”需求,应该就是多“worker”模型(多消费者模型)了,即一个(或多个)进程负责提供数据,多个进程(worker)负责处理(消费)数据。
在shell中启动多个进程的要点,是要用“jobs”控制符 ‘&’启动任务,即将任务放到后台运行。
shell的多进程难点在于如何控制多进程有几个。
解决这个问题,需要巧用管道文件。如下例
batch_job() {
# 花开的地方
# http://www.bsmdap.com/
# 定义并发数量
local num=$1
# 定义“数据”来源
local list_file=$2
# 定义“worker”,传递给“worker”的“位置参数”是数据文件list_file的“行”
shift 2
local action=$@
# 建立管道文件,为了不受“外界”干扰,将文件打开,将文件inode信息删除(删除文件)
local pipe=`mktemp -u`
mkfifo $pipe
# 将文件$pipe绑定到文件句柄6上(打开)
exec 6<> $pipe
rm -f "$pipe"
# 假如并发数大于数据文件行数,即会出错,需要提前处理
local line=`wc -l $list_file|awk '{print $1}'`
if [ "$num" -lt "$line" ] ; then
:
else
num=$line
fi
local i
for((i=0;i<num ;i++)) ; do
echo
done >&6
while read i ; do
read -u 6
( $action $i; echo >&6 ) &
done < $list_file
# 为了不让主进程在读完list_file后就退出(这时很有可能还有$num个后台任务在运行)
# 此处调用wait等待
wait
# 关闭文件句柄6
exec 6>&-
}
#下面这个</num>是wp(或者插件自动生成的,去不掉)
假定我有很多TCP服务,需要检测端口是不是活的,可以先整理一个数据文件vip_list,内容如下:
a.a.a.a 80
b.b.b.b 31
c.c.c.c 100
再定义一个action:
local_ping() {
set $@
local ip=$1
local port=$2
if nc -w2 -z -t $ip $port &>/dev/null ; then
echo "$ip:$port success"
else
echo "$ip:$port failure"
fi
}
然后这样调用
batch_job 10 vip_list local_ping
?把句柄6 绑定到 新建的管道文件后 , 为什么要删除这个管道文件呢
1. 主要原因是这个文件是个临时文件,这里不删除,后面惦记着删除也麻烦。
2. 假如不删除,这个文件还有可能被从外部“注入”数据,影响“多进程”的数量。
另外:还有篇linux下并发处理很nice!内容如下:
#!/bin/bash
tmpfile=$$.fifo #创建管道名称
mkfifo $tmpfile #创建管道
exec 4<>$tmpfile #创建文件标示4,以读写方式操作管道$tmpfile
rm $tmpfile #将创建的管道文件清除
thred=4 #指定并发个数
seq=(1 2 3 4 5 6 7 8 9 21 22 23 24 25 31 32 33 34 35) #创建任务列表
# 为并发线程创建相应个数的占位
{
for (( i = 1;i<=${thred};i++ ))
do
echo; #因为read命令一次读取一行,一个echo默认输出一个换行符,所以为每个线程输
done
} >&4 #将占位信息写入管道
for id in ${seq[*]} #从任务列表 seq 中按次序获取每一个任务
do
read #读取一行,即fd4中的一个占位符
(./ur_command ${id};echo >&4 ) & #在后台执行任务ur_command 并将任务 ${id} 赋给当前任务;任务执行完后在fd4种写入一个占位符
done <&4 #指定fd4为整个for的标准输入
wait #等待所有在此shell脚本中启动的后台任务完成
exec 4>&- #关闭管道
整个流程中read 和 echo 对fd4的交替写入和读取是并发处理的关键
可以想象 如果read 命令发现fd4中没有数据时 将等待fd4的数据
如果可以自动kill掉超时的子任务就更好了
原文:能不能用shell做一个队列 http://www.chinaunix.net/jh/24/675452.ht
r2007 回复于:2005-12-24 19:27:15
#!/bin/bash
tmpfile=$$.fifo
mkfifo $tmpfile
exec 4<>$tmpfile
rm $tmpfile #以上工作---开一包间(一楼4号房间)
{ echo;echo;echo;echo; } >&4 #摆一桌麻将,4张椅子
for (( i = 1 ; i <= 100 ; i++ )) #100个赌鬼排队进场
do
read #赌鬼开始抓风,东西南北,拿椅子按次序坐下
( ur_command $i; echo >&4 ) & #开始打牌ing...;bp机响了,是GF的,归还椅子走人
done <&4
wait #等待最后4个赌鬼打完
nees 回复于:2005-12-25 20:32:11
我在linux下测试通过。
另外我写了一种变体,对于参数不是连续的也可以适用,请大家指正:
#!/bin/bash
tmpfile=$$.fifo
mkfifo $tmpfile
exec 4<>$tmpfile
rm $tmpfile #以上工作---开一包间(一楼4号房间)
thred=4
seq=(1 2 3 4 5 6 7 8 9 21 22 23 24 25 31 32 33 34 35)
#
{
for (( i = 1;i<=${thred};i++ ))
do
echo;
done
} >&4
for id in ${seq[*]}
do
read
(./ur_command ${id};echo >&4 ) &
done <&4
wait