> 文章列表 > Linux系统下使用shell“多线程执行命令”

Linux系统下使用shell“多线程执行命令”

Linux系统下使用shell“多线程执行命令”

前言

在工作中常遇到如下场景:
系统未接入日志中心,系统本身使用集群部署,那么再查找日志的时候只能一台一台的去搜索关键字,后来运维同学发现这样一台一台效率太低了,于是有了升级版,升级之后的方式还是一台一台去搜索只不过这次换成了脚本去执行,原理上还是需要在一台上搜索完成之后再去另一台搜素。如果遇到日志相当多的情况,那这种也会很慢。

下面介绍一种今天新学到的技能,就是使用“多线程”的方式去执行脚本,但是这种多线程并不是类似java中的那种多线程,而是触发了多个进程,这里的多线程可以理解为多进程。

管道

在介绍多进程前,先来学习一下管道,一般说到管道,常使用Linux的同学首先会想到“|”,这个管道的意思是将前面的输出通过管道做为后面的输入,可以理解为是一种传输介质,是Linux的一种通信方式,比如ps -ef | grep test 。

那么还有一种管道是FIFO文件,这种文件也可以完成类似上面的工作,比如 ps -ef > .fifo写入文件, 同时在开个客户端就可以获取到通过如下命令获取到数据,grep test .fifo,实际操作一次会发现在写入文件后,如果另一个客户端不对.fifo做任何操作,那么第一个客户端会阻塞住,直到第二个客户端操作了之后第一个才会结束。

FIFO管道文件和普通文件的区别

1、创建方式不同
FIFO管道文件是通过mkfifo命令创建出来的,而普通文件是通过touch命令创建出来的
2、普通文件写入后不会阻塞,FIFO文件写入后会阻塞
3、普通文件时保存在磁盘上的,而FIFO文件是保存在内存中的

“多线程”的实现思路

初级版本:使用&符配合wait实现,这种适用于确定循环次数并且循环次数不是太多。

for ((i=0;i<5;i++));doecho 1{sleep 3;echo "done!"}&
donewait
echo "执行完毕!!!"

升级版本:利用FiFO管道来控制进程数,达到了“多线程”且线程数可控的目的。
如下脚本中的open_thread()函数还可以封装成一个单独的脚本,使用的时候通过source xxx引入来使用,这样看起来更优雅一些。

#!/usr/bin/env bash
# Describe: grep指定文件夹中的所有文本中的指定关键字 #
# Version: v1.0                                   #
# Author: cz                                      #
# 开启多线程操作
open_thread() {# 最大进程数PROCESS_NUM=$1# 使用mkfifo命令可以使用指定的名称创建先进先出文件(FIFO)# 创建一个fifo文件FIFO_FILE=./$.fifomkfifo $FIFO_FILE# 关联fifo文件和fd6exec 6<>$FIFO_FILE      # 将fd6指向fifo类型rm $FIFO_FILE# 向fd6中输入$PROCESS_NUM个回车echo ${PROCESS_NUM}for((idx=0;idx<${PROCESS_NUM};idx++))doechodone >&6}# 指定文件夹下的文件并行读取
# 支持 grep key_word file_name
#
#
grep_specified_folder () {echo $1echo $2echo $3# 获取指定文件夹folder=$1# 需要grep的关键字key_word=$2# 定义线程数,如果未定义则默认为5,如何判断是未定义呢,通过参数个数来判断PROCESS_NUM=$3# 临时文件名temporary_file_name='~jef_temp_file'# 开启多线程open_thread $3for filename in $(ls $folder)doread -u6# 每个线程处理一个gerp{result=`grep $key_word $folder/$filename`# 将结果追加到文件中echo "=============="$filename"===========" >> $temporary_file_nameecho "$result" >> $temporary_file_name# 当进程结束以后,再向fd6中加上一个回车符,即补上了read -u6减去的那个echo  >&6}&done# 等待所有的任务执行完毕wait# 关闭fd6exec 6>&-cat $temporary_file_namerm $temporary_file_name
}grep_specified_folder $1 $2 $3