Shell脚本并发控制
Shell脚本并发控制
在编写Shell脚本时,有些内部逻辑需要通过并发来提高效率,但并发如何进行控制?下面进行下简单的介绍~
实战场景
举例一个简单的示例,假设要输出数字1到10,且每次输出前sleep 1
即睡眠1秒钟
普通方案
根据场景描述,首先想到的普通方法就是for循环输出:
1 |
|
执行脚本查看,输出10个数字,每次sleep 1
,共耗时10秒:
1 |
|
并行方案
方案1
在命令的末尾使用&
符号,将命令放到后台执行,如果核心业务代码有多条命令,可以将其放到{}
中,然后在大括号后添加&
符号
1 |
|
执行脚本查看,发现先输出的时间然后才是数字,同时前后开始和结束时间一致且中间还有[heibanbai@heibanbai ~]$
,这是因为通过&
,业务代码全部进入了后台执行,脚本主进程在不到1秒钟的时间就已经执行完了
1 |
|
那么如何控制上面出现的问题,在核心业务代码执行完成后再执行后面的代码呢?只需要通过wait
命令即可实现,加上wait
后,将会等待子进程执行结束后再执行后面的语句,修改后脚本如下:
1 |
|
执行脚本查看,在所有数字全部输出后才执行的后续代码,但仔细思量将会发现有一个问题,假如核心业务代码循环次数非常多且又消耗系统资源,那么将会出现什么情况?这就需要对并发进行控制,如何进行控制将通过下面的方法进行介绍
1 |
|
方案2
通过使用管道和文件描述符控制并发数量,这里大概说下两个概念
管道
有无名管道和有名管道两种
无名管道,在日常使用频率超高,比如:
1
ls ./ | wc -l
这里面的
|
就是管道,它将前一个命令的结果输出到后一个进程中,作为两个进程的数据通道,不过他是无名的。使用
mkfifo
命令创建的管道即为有名管道,例如mkfifo pipefile
,pipefile
即为有名管道
有名管道有一个特点:如果管道里没有数据,那么去取管道数据时,程序会阻塞住,直到管道内进入数据,然后读取才会终止这个操作,反之,管道在执行写入操作时,如果没有读取操作,同样会阻塞由此可以得到:利用有名管道的特性就可以实现一个队列的控制。
文件描述符
File Descriptors (FD,文件描述符或文件句柄):进程使用文件描述符来管理打开的文件。文件描述符是与输入和输出流相关联的整数。最广为人知的文件描述符是
stdin
(0)、stdout
(1)和stderr
(2),文件描述符0
、1
以及2
是系统预留的。我们可以将某个文件描述符的内容重定向到另一个文件描述符中文件描述符的值不能乱取,取值范围是
3至(ulimit -n)-1
,ulinit -n
是 系统的open files
,默认一般就是1024,直接输入ulimit -n
就可以查看。一般使用范围是数字0~9,重定向时大于9的文件描述符要谨慎使用,因为可能与Shell内部使用的文件描述符冲突Bash的内部命令exec的功能之一是允许我们操作文件描述符。常用的打开模式有3种:
- 只读模式。
- 追加写入模式。
- 截断写入模式。
<
操作符可以将文件读入stdin
。>
操作符用于截断模式的文件写入(数据在目标文件内容被截断之后写入)。>>
操作符用于追加模式的文件写入(数据被追加到文件的现有内容之后,而且该目标文件中原有的内容不会丢失)。文件描述符可以用以上3种模式中的任意一种来创建。
那么将上述场景进行改造后如下:
1 |
|
执行脚本查看:
1 |
|
蚂蚁🐜再小也是肉🥩!
“您的支持,我的动力!觉得不错的话,给点打赏吧 ୧(๑•̀⌄•́๑)૭”
微信支付
支付宝支付