shell实现并发控制
需求:并发检测1000台web服务器状态(或者并发为1000台web服务器分发文件等)如何用shell实现?
方案-:(这应该是大多数第一时间都想到的方法吧)
思路:一个for循环1000次,顺序执行1000次任务。
实现:
#!/bin/bash
start_time=`date +%s` #定义脚本运行的开始时间 for ((i=1;i<=1000;i++))
do
sleep 1 #sleep 1用来模仿执行一条命令需要花费的时间(可以用真实命令来代替)
echo 'success'$i;
done stop_time=`date +%s` #定义脚本运行的结束时间 echo "TIME:`expr $stop_time - $start_time`"
[root@iZ94yyzmpgvZ ~]# . test.sh
success1
success2
success3
success4
success5
success6
success7
........此处省略
success999
success1000
TIME:1000
代码解析以及问题:
一个for循环1000次相当于需要处理1000个任务,循环sleep 1代表运行一个命令需要的时间,用success$i来标示每条任务。
这样写的问题是,1000条命令都是顺序执行的,完成是阻塞时的运行,假如每条命令的运行时间是1秒的话,那么1000条命令的运行时间是1000秒,效率相当低,
而要求是并发检测1000台web的存活,如果采用这种顺序的方式,那么假如我有1000台web,这时候第900台机器挂掉了,检测到这台机器状态所需要的时间就是900s!
所以,问题关键集中在一点:如何并发
方案二:
思路:一个for循环1000次,循环体里面的每个任务放入后台运行(在命令后面加&符号代表后台运行)。
实现:
bin/bash
start=`date +%s` #定义脚本运行的开始时间 for ((i=1;i<=1000;i++))
do
{
sleep 1 #sleep 1用来模仿执行一条命令需要花费的时间(可以用真实命令来代替)
echo 'success'$i;
}& #用{}把循环体括起来,后加一个&符号,代表每次循环都把命令放入后台运行
#一旦放入后台,就意味着{}里面的命令交给操作系统的一个线程处理了
#循环了1000次,就有1000个&把任务放入后台,操作系统会并发1000个线程来处理
#这些任务
done
wait #wait命令的意思是,等待(wait命令)上面的命令(放入后台的)都执行完毕了再
#往下执行。
#在这里写wait是因为,一条命令一旦被放入后台后,这条任务就交给了操作系统
#shell脚本会继续往下运行(也就是说:shell脚本里面一旦碰到&符号就只管把它
#前面的命令放入后台就算完成任务了,具体执行交给操作系统去做,脚本会继续
#往下执行),所以要在这个位置加上wait命令,等待操作系统执行完所有后台命令
end=`date +%s` #定义脚本运行的结束时间 echo "TIME:`expr $end - $start`"
运行结果:
[root@iZ94yyzmpgvZ /]# . test1.sh
......
[989] Done { sleep 1; echo 'success'$i; }
[990] Done { sleep 1; echo 'success'$i; }
success992
[991] Done { sleep 1; echo 'success'$i; }
[992] Done { sleep 1; echo 'success'$i; }
success993
[993] Done { sleep 1; echo 'success'$i; }
success994
success995
[994] Done { sleep 1; echo 'success'$i; }
success996
[995] Done { sleep 1; echo 'success'$i; }
[996] Done { sleep 1; echo 'success'$i; }
success997
success998
[997] Done { sleep 1; echo 'success'$i; }
success999
[998] Done { sleep 1; echo 'success'$i; }
[999]- Done { sleep 1; echo 'success'$i; }
success1000
[1000]+ Done { sleep 1; echo 'success'$i; }
TIME:2
2.echo “test” > /tmp/fd1(如果没有读管道的操作,则阻塞)
总结:
利用有名管道的上述特性就可以实现一个队列控制了
你可以这样想:一个女士公共厕所总共就10个蹲位,这个蹲位就是队列长度,女侧所门口放着10把钥匙,要想上厕所必须拿一把钥匙,上完厕所后归还钥匙,下一个人就可以拿钥匙进去上厕所了,这样同时来了1千为美女上厕所,那前十个人抢到钥匙进去上厕所了,后面的990人需要等一个出来归还钥匙才可以拿到钥匙进去上厕所,这样10把钥匙就实现了控制1000人上厕所的任务,(os中称之为信号量)
二.文件描述符
1.管道具有存一个读一个,读完一个就少一个,没有则阻塞,放回的可以重复取,这正是队列特性,但是问题是当往管道文件里面放入一段内容,没人取则阻塞,这样你永远也没办法往管道里面同时放入10段内容(想当与10把钥匙),解决这个问题的关键就是文件描述符了。
2.mkfifo /tmp/fd1
创建有名管道文件exec 3<>/tmp/fd1,创建文件描述符3关联管道文件,这时候3这个文件描述符就拥有了管道的所有特性,还具有一个管道不具有的特性:无限存不阻塞,无限取不阻塞,而不用关心管道是否为空。也不用关心是否有内容写入引用文件描述符:&3可以执行n次echo >&3往管道里放入n把钥匙
实现:
#!/bin/bash
start_time=`date +%s` #定义脚本运行的开始时间
[ -e /tmp/fd1 ] || mkfifo /tmp/fd1 #创建有名管道
exec 3<>/tmp/fd1 #创建文件描述符,以可读(<)可写(>)的方式关联管道文件,这时候文件描述符3就有了有名管道文件的所有特性
rm -rf /tmp/fd1 #关联后的文件描述符拥有管道文件的所有特性,所以这时候管道文件可以删除,我们留下文件描述符来用就可以了
for ((i=1;i<=10;i++))
do
echo >&3 #&3代表引用文件描述符3,这条命令代表往管道里面放入了一个"令牌"
done for ((i=1;i<=1000;i++))
do
read -u3 #代表从管道中读取一个令牌
{
sleep 1 #sleep 1用来模仿执行一条命令需要花费的时间(可以用真实命令来代替)
echo 'success'$i
echo >&3 #代表我这一次命令执行到最后,把令牌放回管道
}&
done
wait stop_time=`date +%s` #定义脚本运行的结束时间 echo "TIME:`expr $stop_time - $start_time`"
exec 3<&- #关闭文件描述符的读
exec 3>&- #关闭文件描述符的写
[root@iZ94yyzmpgvZ /]# . test2.sh
success4
success6
success7
success8
success9
success5
......
success935
success941
success942
......
success992
[992] Done { sleep 1; echo 'success'$i; echo 1>&3; }
success993
[993] Done { sleep 1; echo 'success'$i; echo 1>&3; }
success994
[994] Done { sleep 1; echo 'success'$i; echo 1>&3; }
success998
success999
success1000
success997
success995
success996
[995] Done { sleep 1; echo 'success'$i; echo 1>&3; }
TIME:101
shell实现并发控制的更多相关文章
- shell队列实现线程并发控制(转)
需求:并发检测1000台web服务器状态(或者并发为1000台web服务器分发文件等)如何用shell实现? 方案一:(这应该是大多数人都第一时间想到的方法吧) 思路:一个for循环1000次,顺序执 ...
- shell脚本实现并发控制
++++++++++++++++++++++++++++++++++++++++++++++++++标题:shell脚本实现并发控制内容:以ping测试主机存活为例,讲述如何通过命名管道文件以及描述符 ...
- shell 队列实现线程并发控制
需求:并发检测1000台web服务器状态(或者并发为1000台web服务器分发文件等)如何用shell实现? 方案一:(这应该是大多数人都第一时间想到的方法吧) 思路:一个for循环1000次,顺序执 ...
- 我们一起来学Shell - shell的并发及并发控制
文章目录 bash的并发 未使用并发的脚本 简单修改 使用wait命令 控制并发进程的数量 文件描述符 查看当前进程打开的文件 自定义当前进程用描述符号操作文件 管道 我们一起来学Shell - 初识 ...
- (转)shell实例手册
原文地址:http://hi.baidu.com/quanzhou722/item/f4a4f3c9eb37f02d46d5c0d9 实在是太好的资料了,不得不转 shell实例手册 0说明{ 手册制 ...
- 【转载】shell实例手册
原文地址:shell实例手册 作者:没头脑的土豆 shell实例手册 0说明{ 手册制作: 雪松 更新日期: -- 欢迎系统运维加入Q群: 请使用"notepad++"打开此文档 ...
- (转) shell实例手册
shell实例手册 1文件{ touch file # 创建空白文件rm -rf 目录名 # 不提示删除非空目录(-r:递归删除 -f强制)dos2uni ...
- Shell脚本并发及并发数的控制
https://www.jianshu.com/p/701952ffb755 正常情况下,Shell脚本是串行执行的,一条命令执行完才会执行接下来的命令.如下代码: # !/bin/bash for ...
- shell手册
摘自雪松同学 0说明{ # shell实例手册最新下载地址: http://hi.baidu.com/quanzhou722/item/f4a4f3c9eb37f02d46d5c0d9 # pytho ...
随机推荐
- 转换函数conversion function
类转换分为两个角度 转换自身为其他类型 把其他类型转换为自身 Example: 这里我们可以将b转换为class xxx 的类型(方式2),也可以将me转换为double,然后再讲结果转换为doubl ...
- IOI 2005/bzoj 1812:riv 河流
Description 几乎整个Byteland王国都被森林和河流所覆盖.小点的河汇聚到一起,形成了稍大点的河.就这样,所有的河水都汇聚并流进了一条大河,最后这条大河流进了大海.这条大河的入海口处有一 ...
- Windows32或64位下载安装配置Spark
[学习笔记] Windows 32或64位下载安装配置Spark:1)下载地址:http://spark.apache.org/downloads.html 马克-to-win @ 马克java社区: ...
- mysql 连接远程连接服务器 1130错误
今天在用sqlyog连接非本地的Mysql服务器的数据库,居然无法连接很奇怪,报1130错误, ERROR 1130: Host 192.168.3.100 is not allowed to con ...
- (六)Spring 中的 JdbcTemplate
目录 概念 配置数据库 创建 JdbcTemplate 对象 增删改查代码 概念 JdbcTemplate : 是 Spring 中对持久层(JDBC 技术)一个封装 : 使用起来和 Dbutuis ...
- 笔记-2:python基本数据类型
1.数字类型 1.1 整数类型 整数类型有4种进制表示:十进制,二进制,八进制,十六进制,默认情况下,整数采用十进制. 整数类型有4种进制:十进制. 二进制. 八进制和十六进制. 默认情况, 整数采用 ...
- 第11章:使用Python打造MySQL专家系统
1.Python语言高级特性 1).深入浅出Python生成器 1).生成器函数:与普通函数定义类似,使用yield语句而不是return语句返回结果.yield语句一次返回一个结果,在每个结果中间挂 ...
- Spring Boot:上传文件大小超限制如何捕获 MaxUploadSizeExceededException 异常
Spring Boot 默认上传文件大小限制是 1MB,默认单次请求大小是 10MB,超出大小会跑出 MaxUploadSizeExceededException 异常 spring.servlet. ...
- mysql数据库的锁表与解决办法(原博客url:http://www.cnblogs.com/wanghuaijun/p/5949934.html)
MySQL锁概述 相对其他数据库而言,MySQL的锁机制比较简单,其最显著的特点是不同的存储引擎支持不同的锁机制.比如,MyISAM和MEMORY存储引擎采用的是表级锁(table-level loc ...
- Java建造者模式(思维导图)
图1 建造者模式[点击查看大图] 基本的知识点已在思维导图中,下面是demo 1,Builder 为创建一个产品对象的各个部件指定抽象接口 public interface PersonBuilder ...