linux脚本多线程,Linux Shell脚本如何实现多线程

当我们工作中遇到一些批量分发、批量执行场景时,写的一些shell脚本都是单线程任务,当然这些量级不大的时候,看不出劣势。

举个例子:现在需要通过跳板机,分发一个文件到10台服务器,每台服务器传输需要1s时间,10台服务器传输完就是10s。看下面脚本,这里通过sleep命令模拟传输耗时。

#!/bin/bash

#Author: www.amd5.cn

#Description: 模拟分发文件到10台服务器

startTime=`date +%s`

for i in `seq 10`;do

echo $i

sleep 1

done

stopTime=`date +%s`

echo "耗时: $[$stopTime - $startTime] s"

这个执行结果不用思考,就是10s。

# bash test.sh

1

2

3

4

5

6

7

8

9

10

耗时: 10 s

如果是500台服务器或者1000台服务器,那命令执行以后就慢慢等吧。那如果文件比较大,一个需要30s呢?1000 * 30 =30000 s 基本上就是8个多小时。早上上班执行,等到下班刚刚好,如果你的脚本是前台运行,中间突然网络波动,导致远程断开了,那就厕所哭去吧。

其实文件分发大不了就是等嘛,但是如果是批量检查服务器状态,或者批量启动服务,服务器数量一大,那劣势就特别明显了。

那么有没有办法提高效率呢?答案是肯定的,利用多线程,本来需要10s完成的任务,我使用了5个线程,那么跑下来基本也就2s左右。shell不像 python、go语言,他们本身就有多线程模块。

shell只能利用管道和文件描述符实现多线程任务,直接脚本测试刚才的分发文件。

#!/bin/bash

#Author: www.amd5.cn

#Description: 模拟多线程分发文件到10台服务器

startTime=`date +%s`

tmpfifo="/tmp/$$.fifo"

[ -e $tmpfifo ] || mkfifo $tmpfifo

exec 3<>$tmpfifo

rm -rf $tmpfifo

for i in `seq 5`;do

echo >&3

done

for i in `seq 10`;do

read -u3

{

sleep 1

echo $i

echo >&3

}&

done

wait

stopTime=`date +%s`

echo "耗时: $[$stopTime - $startTime] s"

exec 3

exec 3>&-

执行结果如下图:

64f8bbd6eff78711695d4d25735ebafd.gif

如果是10个线程,结果就是1s,如果是6、7、8、9个线程,整个任务执行完也是2s,所以需要根据实际的情况设置线程数,也并不是线程越多越好,整个要看本身执行脚本的服务器CPU核数以及其它资源情况。

下面对脚本语句进行分析:

#!/bin/bash

#Author: www.amd5.cn

#Description: 模拟多线程分发文件到10台服务器

startTime=`date +%s`

tmpfifo="/tmp/$$.fifo"

#判断有名管道是否存在 创建有名管道文件

[ -e $tmpfifo ] || mkfifo $tmpfifo

#创建文件描述符 exec 3<>$tmpfifo,(可读())创建文件描述符3关联管道文件,这时候3这个文件描述符就拥有了管道的所有特性。

#还具有一个管道不具有的特性:无限存不阻塞,无限取不阻塞,而不用关心管道内是否为空,也不用关心是否有内容写入引用文件描述符: &3可以执行n次echo >&3 往管道里放入n把钥匙。并发n

exec 3<>$tmpfifo

#关联后的文件描述符拥有管道文件的所有特性,所以这时候管道文件可以删除,留下文件描述符来用就可以了。

rm -rf $tmpfifo

for i in `seq 5`;do

#&3代表引用文件描述符3,这条命令代表往管道里面放入了一个"令牌",`seq 5` 循环5次,也就是5个令牌,即5个线程

echo >&3

done

for i in `seq 10`;do

#代表从管道中读取一个令牌

read -u3

{

sleep 1

echo $i

#代表我这一次命令执行到最后,把令牌放回管道

echo >&3

}&   #用{}把循环体括起来,后加一个&符号,代表每次循环都把命令放入后台运行

done

#wait命令的意思是,等待(wait命令)上面的命令(放入后台的)都执行完毕了再往下执行

wait

stopTime=`date +%s`

echo "耗时: $[$stopTime - $startTime] s"

#关闭文件描述符的读

exec 3

#关闭文件描述符的写

exec 3>&-

其实主要就是mkfifo和exec两个命令的使用。

exec命令

用于调用并执行指令的命令。exec命令通常用在shell脚本程序中,可以调用其他的命令。如果在当前终端中使用命令,则当指定的命令执行完毕后会立即退出终端。

Linux每打开一个shell就会打开默认的三个文件描述符描0,1,2,分别代表标准输入,标准输出和标准错误输出。需要的时候我们可以使用exec命令指定一个大于3的数字作为文件。

1、exec 3

2、exec 3>/tmp/1.txt     #以“只写方式”打开/tmp/1.txt,文件描述符对应为3

3、exec 3<>/tmp/1.txt    #以“读写方式”打开/tmp/1.txt,文件描述符对应为3

4、exec 3

转载请注明:阿汤博客->Linux Shell脚本如何实现多线程 http://www.amd5.cn/atang_4575.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值