shell并发

备忘一个脚本.


又一篇写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.html
 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




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值