shell多进程与管道

前言

并发编程很常见,因为在绝大多数场景下,业务上对任务的完成时间都是有要求的,一般情况并发度越高,任务的完成速度就越快。那么如何在 shell 里面实现部分代码块的并发执行呢?如何控制并发数量呢?

管道

匿名管道

匿名管道就是我们常见的管道符 |,匿名管道的两端是两个文件描述符,一个只读端,一个只写端,这样其他的进程就无法连接到此匿名管道。
比如 impala-shell -q sql | python xx.py,shell 会创建两个进程来执行 imapla-shell 和 python 程序,impala-shell 进程的标准输出(文件描述符1)会作为 python 脚本的标准输入(文件描述符0)。两个进程之间并不知道管道的存在,只是从文件描述符中读取或者写入数据,内部实现被包在了 shell 里面。

命名管道

命名管道即 FIFO,具有和匿名管道一样的性质,但是需要注意以下几点

  • 命名管道存在于文件系统中,作为特殊文件存在
  • 命名管道是双向字节流,读写缺少其一,便会堵塞
  • 匿名管道是 shell 自动创建的,命名管道是由程序创建的(mkinfo),存在于文件系统中

& 实现多进程,管道控制并发数量

& 可以把程序放到后台执行
命名管道用于控制并发数量

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
# 接收 SIGINT 信号(ctrl+C),关闭文件描述符读写并退出程序
trap "exec 10>&-;exec 10<&-;exit 0" 2

thread_num=10

# 创建管道文件
tempfifo="my.fifo"
mkfifo ${tempfifo}
# 将文件描述符与管道文件绑定
exec 10<>${tempfifo}
# 为啥创建了又删除不太清楚
rm -f ${tempfifo}
# 向管道文件中写入空行,控制并发数
for ((i=1;i<=${thread_num};i++)); do
echo >&10
done

for i in `seq 1 100`
do
# 读取管道内容,并放到后台执行
read -u10
{
echo "sleep 10 "
sleep 10
# 上面任务执行完后,在写入一行,避免阻塞任务
echo >&10
} &
done
# 等待上述子进程执行完,并关闭文件描述符读写
wait
exec 10>&-
exec 10<&-
使用搜索:谷歌必应百度