shell多进程
shell中没有多进程的概念,可以通过开启子shell并在后台执行来实现并发。
串行执行
#!/bin/bash
start=`date +"%s"`
for (( i=0; i<10; i++ ))
do
{
echo "execute"
sleep 1
}
done
end=`date +"%s"`
echo "time: " `expr $end - $start`12
1
2
start=`date +"%s"`3
for (( i=0; i<10; i++ ))4
do5
{6
echo "execute"7
sleep 18
}9
done10
11
end=`date +"%s"`12
echo "time: " `expr $end - $start` 执行时间为10秒
并发执行
让for循环中的代码在后台子shell中执行,只需在for循环的结尾加上&,并且在for循环外加上wait语句,等待子进程结束即可。
#!/bin/bash
start=`date +"%s"`
for (( i=0; i<10; i++ ))
do
{
echo "execute"
sleep 1
}&
done
wait
end=`date +"%s"`
echo "time: " `expr $end - $start`12
1
2
start=`date +"%s"`3
for (( i=0; i<10; i++ ))4
do5
{6
echo "execute"7
sleep 18
}&9
done10
wait11
end=`date +"%s"`12
echo "time: " `expr $end - $start` 执行时间为1秒,速度提升了10倍。
这种方式比较简单,但是有个弊端,无法控制子进程的数量,如果循环一万次,会产生一万个子进程,造成不可预期的情况。
可以通过命名管道来控制子进程的数量
管道可以用于进程间通信,一个进程向管道中写入数据,同时另一个进程从管道中读取数据,管道为空进程会被阻塞,只有一个进程读或者一个进程写管道时,进程也会被阻塞。
通常使用的 cat | grep name 中的 | 是无名管道。
利用命令管道控制并发数量的实例
#!/bin/bash
fd_fifo=/tmp/fd_1
mkfifo $fd_fifo #创建命令管道(pipe类型文件)
exec 6<>$fd_fifo #将管道的fd与6号fd绑定
proc_num=5 #进程个数
count=0;
#预分配资源
for ((i=0;i<$proc_num;i++))
do
echo >& 6 #写入一个空行
done
start=`date +"%s"
for (( i=0; i<10; i++ ))
do
read -u 6 #读取一个空行
{
echo "execute"
sleep 1
echo >& 6 #完成任务,写入一个空行
}& #后台执行
done
wait #等待所有的任务完成
exec 6>&- #关闭fd 6描述符,stdou和stdin
exec 6<&-
rm -f $fifo #删除管道
end=`date +"%s"`
echo "time: " `expr $end - $start`x
1
2
3
fd_fifo=/tmp/fd_1 4
mkfifo $fd_fifo #创建命令管道(pipe类型文件)5
exec 6<>$fd_fifo #将管道的fd与6号fd绑定6
proc_num=5 #进程个数7
count=0;8
#预分配资源9
for ((i=0;i<$proc_num;i++))10
do11
echo >& 6 #写入一个空行12
done13
14
start=`date +"%s"15
for (( i=0; i<10; i++ ))16
do17
read -u 6 #读取一个空行18
{19
echo "execute"20
sleep 121
echo >& 6 #完成任务,写入一个空行22
}& #后台执行23
done24
wait #等待所有的任务完成25
exec 6>&- #关闭fd 6描述符,stdou和stdin26
exec 6<&- 27
rm -f $fifo #删除管道28
29
end=`date +"%s"`30
echo "time: " `expr $end - $start`执行时间为2秒(每次有5个进程在同时执行)
初始化向管道中写入5行空字符
父shell进程执行read -u 6,会从管道中读取一行,当管道为空时read -u会阻塞,保证最多只有5个shell进程在后台执行。
子shell进程执行echo >& 6,会向管道中写入一行,父shell进程阻塞状态解除,可以继续开启子shell执行任务。
父shell进程执行完10次循环后,调用wait函数,等待子shell执行完毕,回收资源。
如果不加上wait语句,父进程会直接退出,导致子进程成为孤儿进程(孤儿进程为被pid为1的init进程接管);或者子进程提前退出,父进程未执行完但不知道子进程的退出状态,会使子进程成为僵尸进程。
父进程的变量会被复制一份到子进程中,变量在子进程中的任何修改不会影响父进程中的变量。
浙公网安备 33010602011771号