免费注册 查看新帖 |

Chinaunix

广告
  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 9004 | 回复: 14
打印 上一主题 下一主题

多线程脚本的控制办法 [复制链接]

论坛徽章:
2
白羊座
日期:2013-11-18 19:52:42辰龙
日期:2014-09-07 07:46:06
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2012-06-13 08:45 |只看该作者 |倒序浏览
本帖最后由 damcool 于 2012-06-13 09:02 编辑

在脚本中为了提高运行效率,我们一般都会引入多线程运行个脚本函数的方法。但是之后需要等待所有并发的线程结束,我这里分享一个简单的办法。原理是用数组纪录线程的进程ID,逐一比对存在情况。下面给出两个例程一个是为了直观看到运行结果,后一个是实际使用的方法。
演示的例子:
  1. #!/bin/bash
  2. function hello_thread(){
  3.         echo "thread $1 start at `date`"
  4.         sleep 10
  5. }
  6. thread_pid=()
  7. for i in `seq 9`; do
  8.         hello_thread $i &
  9.         thread_pid=("${thread_pid[@]}" "$!")
  10. done
  11. while [ ${#thread_pid[@]} -ne 0 ]; do
  12.         for pid_idx in ${!thread_pid[*]}; do
  13.                 pid_val=${thread_pid[$pid_idx]}
  14.                 if [ ${#pid_val} -ne 0 ]; then
  15.                     kill -s 0 $pid_val &>/dev/null
  16.                     [ $? -ne 0 ] && unset thread_pid[$pid_idx] && echo "thread $(($pid_idx+1)) dead at `date`"
  17.                 fi
  18.         done
  19. done
复制代码
演示结果:
[damcool@centos test]$ sh test.sh
thread 5 start at 2012年 06月 13日 星期三 08:48:27 CST
thread 1 start at 2012年 06月 13日 星期三 08:48:27 CST
thread 3 start at 2012年 06月 13日 星期三 08:48:27 CST
thread 8 start at 2012年 06月 13日 星期三 08:48:27 CST
thread 9 start at 2012年 06月 13日 星期三 08:48:27 CST
thread 6 start at 2012年 06月 13日 星期三 08:48:27 CST
thread 2 start at 2012年 06月 13日 星期三 08:48:27 CST
thread 7 start at 2012年 06月 13日 星期三 08:48:27 CST
thread 4 start at 2012年 06月 13日 星期三 08:48:27 CST
thread 3 dead at 2012年 06月 13日 星期三 08:48:37 CST
thread 5 dead at 2012年 06月 13日 星期三 08:48:37 CST
thread 8 dead at 2012年 06月 13日 星期三 08:48:37 CST
thread 9 dead at 2012年 06月 13日 星期三 08:48:37 CST
thread 1 dead at 2012年 06月 13日 星期三 08:48:37 CST
thread 2 dead at 2012年 06月 13日 星期三 08:48:37 CST
thread 6 dead at 2012年 06月 13日 星期三 08:48:37 CST
thread 7 dead at 2012年 06月 13日 星期三 08:48:37 CST
thread 4 dead at 2012年 06月 13日 星期三 08:48:37 CST

实际使用中的例子:
  1. #!/bin/bash
  2. function hello_thread(){
  3.         echo "thread $1 start at `date`"
  4.         sleep 10
  5. }
  6. thread_pid=()
  7. for i in `seq 9`; do
  8.         hello_thread $i &
  9.         thread_pid=("${thread_pid[@]}" "$!")
  10. done
  11. while [ ${#thread_pid[@]} -ne 0 ]; do
  12.         for pid_idx in ${!thread_pid[*]}; do
  13.                 pid_val=${thread_pid[$pid_idx]}
  14.                 kill -s 0 $pid_val &>/dev/null || unset thread_pid[$pid_idx]
  15.         done
  16.         thread_pid=("${thread_pid[@]}")
  17.         sleep 30
  18. done
复制代码

评分

参与人数 1可用积分 +6 信誉积分 +2 收起 理由
zooyo + 6 + 2 感谢分享

查看全部评分

论坛徽章:
2
白羊座
日期:2013-11-18 19:52:42辰龙
日期:2014-09-07 07:46:06
2 [报告]
发表于 2012-06-13 08:53 |只看该作者
本帖最后由 damcool 于 2012-06-13 09:38 编辑

另外有的时候我们还需要控制并发线程的数量。那么这时候我们的代码就要这样了
  1. #!/bin/bash
  2. function hello_thread(){
  3.         echo "thread $1 start at `date`"
  4.         sleep 10
  5.         echo "thread $1 dead at `date`"
  6. }
  7. thread_pid=()
  8. SESSION_LIMT=3
  9. for i in `seq 9`; do
  10. #确认当前线程数量没有超过控制
  11.         while [ ${#thread_pid[@]} -ge $SESSION_LIMT ]; do
  12.                 for pid_idx in ${!thread_pid[*]}; do
  13.                        pid_val=${thread_pid[$pid_idx]}
  14.                        kill -s 0 $pid_val &>/dev/null || unset thread_pid[$pid_idx]
  15.                  done
  16.                  thread_pid=("${thread_pid[@]}")
  17.         done;
  18.         hello_thread $i &
  19.         thread_pid=("${thread_pid[@]}" "$!")
  20. done
  21. while [ ${#thread_pid[@]} -ne 0 ]; do
  22.         for pid_idx in ${!thread_pid[*]}; do
  23.                 pid_val=${thread_pid[$pid_idx]}
  24.                 kill -s 0 $pid_val &>/dev/null || unset thread_pid[$pid_idx]
  25.         done
  26. done
复制代码
[damcool@centos test]$ sh test.sh
thread 3 start at 2012年 06月 13日 星期三 09:14:09 CST
thread 2 start at 2012年 06月 13日 星期三 09:14:09 CST
thread 1 start at 2012年 06月 13日 星期三 09:14:09 CST
thread 2 dead at 2012年 06月 13日 星期三 09:14:19 CST
thread 3 dead at 2012年 06月 13日 星期三 09:14:19 CST
thread 4 start at 2012年 06月 13日 星期三 09:14:19 CST
thread 5 start at 2012年 06月 13日 星期三 09:14:19 CST
thread 1 dead at 2012年 06月 13日 星期三 09:14:19 CST
thread 6 start at 2012年 06月 13日 星期三 09:14:19 CST
thread 4 dead at 2012年 06月 13日 星期三 09:14:29 CST
thread 5 dead at 2012年 06月 13日 星期三 09:14:29 CST
thread 7 start at 2012年 06月 13日 星期三 09:14:29 CST
thread 8 start at 2012年 06月 13日 星期三 09:14:29 CST
thread 6 dead at 2012年 06月 13日 星期三 09:14:29 CST
thread 9 start at 2012年 06月 13日 星期三 09:14:29 CST
thread 7 dead at 2012年 06月 13日 星期三 09:14:39 CST
thread 8 dead at 2012年 06月 13日 星期三 09:14:39 CST
thread 9 dead at 2012年 06月 13日 星期三 09:14:39 CST

从这里我们可以看出,我们将线程数量的阀值设成3,保证同时只能由3个线程在运行。这样可以提高效率的同时又不让系统负载太大。
细心的朋友可能发现1号线程为什么不是第一个输出,好像输出顺序有点奇怪。这里我们要将另一个问题,线程资源控制。
  1. #!/bin/bash
  2. function hello_thread(){
  3. #利用目录创建这一动作来实现资源信号互锁
  4.         while [ $(mkdir /tmp/screen &>/dev/null && echo "ok" || echo "ng") != "ok" ]; do
  5.                 sleep 1
  6.         done;
  7.         echo "thread $1 start at `date`"
  8. #是用完资源信号要释放
  9.         rm -rf /tmp/screen
  10.         sleep 10
  11. #利用目录创建这一动作来实现资源信号互锁
  12.         while [ $(mkdir /tmp/screen &>/dev/null && echo "ok" || echo "ng") != "ok" ]; do
  13.                 sleep 1
  14.         done;
  15.         echo "thread $1 dead at `date`"
  16. #是用完资源信号要释放
  17.         rm -rf /tmp/screen
  18. }
  19. thread_pid=()
  20. SESSION_LIMT=3
  21. for i in `seq 9`; do
  22. #确认当前线程数量没有超过控制
  23.         while [ ${#thread_pid[@]} -ge $SESSION_LIMT ]; do
  24.                 for pid_idx in ${!thread_pid[*]}; do
  25.                        pid_val=${thread_pid[$pid_idx]}
  26.                        kill -s 0 $pid_val &>/dev/null || unset thread_pid[$pid_idx]
  27.                  done
  28.                  thread_pid=("${thread_pid[@]}")
  29.         done;
  30.         hello_thread $i &
  31.         thread_pid=("${thread_pid[@]}" "$!")
  32. done
  33. while [ ${#thread_pid[@]} -ne 0 ]; do
  34.         for pid_idx in ${!thread_pid[*]}; do
  35.                 pid_val=${thread_pid[$pid_idx]}
  36.                 kill -s 0 $pid_val &>/dev/null || unset thread_pid[$pid_idx]
  37.         done
  38. done
复制代码
运行结果:[让你失望了,由于系统进程调度策略的问题,显示还是有点乱,不过我相信方法大家都了解了]
[damcool@centos test]$ sh test.sh
thread 3 start at 2012年 06月 13日 星期三 09:31:19 CST
thread 1 start at 2012年 06月 13日 星期三 09:31:19 CST
thread 2 start at 2012年 06月 13日 星期三 09:31:20 CST
thread 3 dead at 2012年 06月 13日 星期三 09:31:29 CST
thread 4 start at 2012年 06月 13日 星期三 09:31:29 CST
thread 2 dead at 2012年 06月 13日 星期三 09:31:30 CST
thread 1 dead at 2012年 06月 13日 星期三 09:31:30 CST
thread 6 start at 2012年 06月 13日 星期三 09:31:30 CST
thread 5 start at 2012年 06月 13日 星期三 09:31:31 CST
thread 4 dead at 2012年 06月 13日 星期三 09:31:39 CST
thread 7 start at 2012年 06月 13日 星期三 09:31:39 CST
thread 6 dead at 2012年 06月 13日 星期三 09:31:40 CST
thread 8 start at 2012年 06月 13日 星期三 09:31:40 CST
thread 5 dead at 2012年 06月 13日 星期三 09:31:41 CST
thread 9 start at 2012年 06月 13日 星期三 09:31:41 CST
thread 7 dead at 2012年 06月 13日 星期三 09:31:49 CST
thread 8 dead at 2012年 06月 13日 星期三 09:31:50 CST
thread 9 dead at 2012年 06月 13日 星期三 09:31:51 CST


论坛徽章:
0
3 [报告]
发表于 2012-06-13 10:46 |只看该作者
感谢分享!

论坛徽章:
0
4 [报告]
发表于 2012-06-13 17:52 |只看该作者
强、顶一个

论坛徽章:
0
5 [报告]
发表于 2012-06-13 18:51 |只看该作者
学习了,收藏,lz绝对是c高手,kill -s 0 这个要看kill的源代码才知道的
如果信号为0,然后发送任何信号,但仍然执行错误检查,这可以用来检查一个进程ID或进程组ID的存在。

论坛徽章:
0
6 [报告]
发表于 2012-11-03 10:25 |只看该作者
学习了,顶

论坛徽章:
0
7 [报告]
发表于 2012-12-10 18:51 |只看该作者
首先膜拜一下大神,其次咨询一下,该shell通过$!把子进程加到数组中

会不会有时候出现最后一个pid不是你后台运行的子进程,可能时来自其它的进程?
其次我运行时出现这样的报错,这个是因为如果该子进程已经结束了,如果还通过kill -s 0 pid会报这样的错?
shuzu.sh: line 17: kill: (93 - No such process
shuzu.sh: line 17: kill: (936) - No such process

谢谢了

论坛徽章:
2
白羊座
日期:2013-11-18 19:52:42辰龙
日期:2014-09-07 07:46:06
8 [报告]
发表于 2013-04-07 17:09 |只看该作者
bio_tt 发表于 2012-12-10 18:51
首先膜拜一下大神,其次咨询一下,该shell通过$!把子进程加到数组中

会不会有时候出现最后一个pid不是你 ...

我的脚本中将kill出错输出都mute了,所以不会有出错提示,另外如果出错的话,下面的判断就可知道该进程已结束。另根据$!的定义可知其获取的pid是上条命令的pid.

论坛徽章:
6
摩羯座
日期:2013-08-24 10:43:10狮子座
日期:2013-08-25 10:27:06天秤座
日期:2013-09-11 20:28:44午马
日期:2014-09-28 16:06:0015-16赛季CBA联赛之八一
日期:2016-12-19 13:55:0515-16赛季CBA联赛之天津
日期:2016-12-20 14:01:23
9 [报告]
发表于 2013-04-07 19:12 |只看该作者
谢谢分享,学习!

论坛徽章:
16
IT运维版块每日发帖之星
日期:2015-08-24 06:20:00综合交流区版块每日发帖之星
日期:2015-10-14 06:20:00IT运维版块每日发帖之星
日期:2015-10-25 06:20:00IT运维版块每日发帖之星
日期:2015-11-06 06:20:00IT运维版块每日发帖之星
日期:2015-12-10 06:20:00平安夜徽章
日期:2015-12-26 00:06:302016猴年福章徽章
日期:2016-02-18 15:30:34IT运维版块每日发帖之星
日期:2016-04-15 06:20:00IT运维版块每日发帖之星
日期:2016-05-21 06:20:00综合交流区版块每日发帖之星
日期:2016-08-16 06:20:002015七夕节徽章
日期:2015-08-21 11:06:17IT运维版块每日发帖之星
日期:2015-08-14 06:20:00
10 [报告]
发表于 2013-04-07 20:30 |只看该作者
此贴mark,收藏。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP