普通多进程
原理
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数据重定向(输入重定向与输出重定向)详细分析