Shell脚本实现多进程并发以及并发数控制

在使用shell的过程中,经常会遇到这样的情况:有很多任务相同的命令需要同时运行,如果按循环顺序执行会很慢,但是如果全部提交到后台执行,系统又承受不住。这时候就需要实现自动将N个任务放到后台并发执行。

这段代码是将所有命令同时提交到后台执行,稍作改变就能控制提交的数目。

for x in `cat pep.list`;
do
    {
        # cmd        
        transposonPSI.pl $x prot #要执行的命令
        # cmd       
    } &
done

为了控制进程,需要引入管道和文件操作符。

管道分为无名管道和有名管道(fifo, first in first out)。无名管道就是常用的|。有名管道通过mkfifo创建,可以理解为把|这个符号用文件代替。mkfifo fifofile后会生成fifofile文件,文件类型标识为p,表示管道,不占磁盘空间。

prw-r--r-- 1 zzq users     0 Oct  7 16:47 fifofile

1、Linux下七种文件类型

文件类型标识 文件类型

  • 普通文件 d 目录 l 符号链接 s(伪文件) 套接字 b(伪文件) 块设备 c(伪文件) 字符设备 p(伪文件) 管道

2、占用存储空间的类型:文件、目录、符号链接。符号链接记录的是路径,路径不长时存在innode里面。

 其他四种:套接字、块设备、字符设备、管道是伪文件,不占用磁盘空间。

———————————————— 版权声明:本文为CSDN博主「huygft」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/linkvivi/article/details/79834143

管道两端要同时有读与写的进程,否则管道的数据流通就会阻塞。

利用管道的这个特性,首先在管道中写入n个空白行,然后再读取一次管道中的一行,执行一次任务,任务在后台执行完后,向管道中写入一个空行。在后台放n个任务后,也就是读入n行后,如果任务没有执行完,就不会写入空行,那么read就没有读入的数据,也就不能继续提交,所以就把后台的线程数控制在了n。

另外,管道还有一个特性,就是读写中缺失一个操作,另外一个操作就是滞留,将文件描述符和管道绑定可以解决这个问题。

文件描述符(缩写fd)在形式上是一个非负整数。实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。每一个unix进程,都会拥有三个标准的文件描述符,来对应三种不同的流:

文件描述符 名称 0 Standard Input 1 Standard Output 2 Standard Error

在 /proc/self/fd 中 可以看到这三个对应文件。 每一个文件描述符会对应一个打开文件,同时,不同的文件描述符也可以对应同一个打开文件;同一个文件可以被不同的进程打开,也可以被同一个进程多次打开。

exec 指令自行定义、绑定文件操作符,文件操作符一般从3-(n-1)都可以随便使用,此处的n 为 ulimit -n 的定义值得到:

[zzq@node9 test]$ ulimit -n
1024

这里的n为1024,所以文件操作符只能使用 0-1023,可自行定义的 就只能是 3-1023 。

如果直接使用管道,把空行写道管道中,只有写入没有读取的操作的话:

echo > fifofile

可以发现,它会一直停滞在那里。所以如果直接用管道来操作的话会在echo那一步停滞。而将管道和文件描述符绑定后,由于同一个文件可以被不同的进程打开,就不会造成停滞。

以下是修改后的代码:

#! /bin/bash

#exec 1000>&-;表示关闭文件描述符1000的写
#exec 1000<&-;表示关闭文件描述符1000的读
#trap是捕获中断命令
trap "exec 1000>&-;exec 1000<&-;exit 0" 2 #接受信号2(ctrl +C)做的操作,表示在脚本运行过程中,如果接收到Ctrl+C中断命令,则关闭文件描述符1000的读写,并正常退出。
FIFO_FILE=$$.fifo  # $表示当前执行文件的PID
mkfifo $FIFO_FILE  #创建管道文件
exec 1000<>$FIFO_FILE #将管道文件和文件操作符绑定

rm -rf $FIFO_FILE	#删除管道文件

# 并行数目
PROCESS_NUM=20
for ((idx=0; idx<$PROCESS_NUM; idx++));
do
    echo>&1000 #对文件操作符进行写入操作,通过for循环写入空行,空行数目为定义的后台线程数量
done

for x in `cat pep.list`;
do
    read -u1000 #从文件描述符读入空行。read -u 后面跟fd,从文件描述符中读入,该文件描述符可以是exec新开启的。
    {
        # cmd        
        transposonPSI.pl $x prot #要执行的命令
        # cmd
        echo >&1000 #上一条命令执行完毕后,在文件描述符中写入空行
    } & # &表示进程放到linux后台执行
done

wait #wait指令等待所有后台进程执行结束
exec 1000>&- #表示关闭文件描述符1000的写

参考:

Linux Shell多进程并发控制

Linux Shell通过fifo实现多进程并发以及并发数控制

shell中的多进程【并发】

Licensed under CC BY-NC-SA 4.0
Built with Hugo
Theme Stack designed by Jimmy

本站访客数人次 总访问量 本文阅读量