shell并发操作

Catalogue
  1. 1. 普通多进程
    1. 1.1. 原理
    2. 1.2. 例子
  2. 2. 使用FIFO实现“多进程”
    1. 2.1. 原理
    2. 2.2. 例子
  3. 3. 管道FIFO
    1. 3.1. 基础知识
      1. 3.1.1. 文件描述符(fd)
      2. 3.1.2. 命名管道
  4. 4. 参考

普通多进程

原理

shell中实现并发,就是把循环体的命令用&符号放入后台运行,1000个任务就会并发1000个线程,运行时间2s左右,比起方案一的1000s,已经非常快了。

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/bin/bash
# bam to bed

date # 脚本开始时间

for ((i=1;i<=1000;i++))
do
{
sleep 1 #sleep 1用以模仿执行一条命令需要花费的时间(可以用真实命令来代替)
echo 'success'$i;
}& #用{}把循环体括起来,后加一个&符号,代表每次循环都把命令放入后台运行
#一旦放入后台,就意味着{}里面的命令交给操作系统的一个线程处理了
#循环了1000次,就有1000个&将任务放入后台,操作系统会并发1000个线程来处理
done
wait #wait命令表示。等待上面的命令(放入后台的任务)都执行完毕了再往下执行

date # 脚本结束时间

使用FIFO实现“多进程”

可以控制每次并发的数量

原理

先新建一个FIFO,写入一些字符。一个进程开始前会先从这个FIFO中读走一个字符,执行完之后再写回一个字符。如果FIFO中没有字符,该线程就会等待,fifo就成了一个锁。

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#!/bin/bash
# bam to bed

start_time=`date +%s` #定义脚本运行的开始时间

tmp_fifofile="/tmp/$$.fifo"
mkfifo $tmp_fifofile # 新建一个FIFO类型的文件
exec 6<>$tmp_fifofile # 将FD6指向FIFO类型
rm $tmp_fifofile #删也可以,

thread_num=5 # 定义最大线程数

#根据线程总数量设置令牌个数
#事实上就是在fd6中放置了$thread_num个回车符
for ((i=0;i<${thread_num};i++));do
echo
done >&6

for i in data/*.bam # 找到data文件夹下所有bam格式的文件
do
# 一个read -u6命令执行一次,就从FD6中减去一个回车符,然后向下执行
# 当FD6中没有回车符时,就停止,从而实现线程数量控制
read -u6
{
echo "great" # 可以用实际命令代替
echo >&6 # 当进程结束以后,再向FD6中加上一个回车符,即补上了read -u6减去的那个
} &
done

wait # 要有wait,等待所有线程结束

stop_time=`date +%s` # 定义脚本运行的结束时间
echo "TIME:`expr $stop_time - $start_time`" # 输出脚本运行时间

exec 6>&- # 关闭FD6
echo "over" # 表示脚本运行结束

管道FIFO

基础知识

文件描述符(fd)

Linux shell中的File Descripter(文件描述符,缩写fd)可以理解为一个指向文件的指针。

默认有三个FD:0,1,2。

1
2
3
0 Standard Input 标准输入
1 Standard Output 正确输出
2 Standard Error 错误输出

除了上面三个标准的描述符外,我们还可以在进程中去自定义其他的数字作为文件描述符,后面例子中会出现自定义数字。每一个文件描述符会对应一个打开文件,同时,不同的文件描述符也可以对应同一个打开文件;同一个文件可以被不同的进程打开,也可以被同一个进程多次打开。(跟匿名管道相比;普通管道:私家车,FIFO管道:公车)

命名管道

我们之前接触过的管道“1”,其实叫做匿名管道,它左边的输出作为右边命令的输入。这个匿名管道只能为两边的命令提供服务,它是无法让其他进程连接的。

实际上,这两个进程(cat和less)并不知道管道的存在,它们只是从标准文件描述符中读取数据和写入数据。

另外一种管道叫做命名管道,英文(First In First Out,简称FIFO)。

1
2
3
4
5
6
7
8
9
FIFO本质上和匿名管道的功能一样,只不过它有一些特点:

1)在文件系统中,FIFO拥有名称,并且是以设备特俗文件的形式存在的;
2)任何进程都可以通过FIFO共享数据;
3)除非FIFO两端同时有读与写的进程,否则FIFO的数据流通将会阻塞;
4)匿名管道是由shell自动创建的,存在于内核中;而FIFO则是由程序创建的(比如mkfifo命令),存在于文件系统中;
5)匿名管道是单向的字节流,而FIFO则是双向的字节流;

有了上面的基础知识储备后,下面我们来用FIFO来实现shell的多进程并发控制。

参考

Linux 1 Shell“ 多线程”,提高工作效率

Linux Shell命名管道FIFO - 多进程动态并发

【转】Linux shell IO重定向

linux shell数据重定向(输入重定向与输出重定向)详细分析