linux c控制进程并发量,shell控制多个进程并发执行实例

shell中实现多进程实际上就是将多个任务放到后台中执行而已,但是现在需要控制多进程并发的数量该如何实现呢?别急,我们一步一步来实现这个目标,首先从最原始的串行执行开始:

#!/bin/bash

start=`date +%s`

for i in $(seq 1 5); do

echo linuxidc.com

sleep 2

done

end=`date +%s`

time=$(($end - $start))

echo "time: $time"

执行结果:

linuxidc@linuxidc:~/linuxidc.com$ ./linuxidc.com.sh

linuxidc.com

linuxidc.com

linuxidc.com

linuxidc.com

linuxidc.com

time: 10

a70053cc888ffa9f3c9eb9c3057003c5.png

这是最原始的一种处理方式,串行执行,无法有效利用计算机的资源,并且效率低下。如果可以一次执行多个任务的,把它放到后台即可,我们做如下改进:

#!/bin/bash

start=`date +%s`

for i in $(seq 1 5); do

{

echo linuxidc.com

sleep 2

}&

done

wait

end=`date +%s`

time=$(($end - $start))

echo "time: $time"

首先看下执行结果:

linuxidc@linuxidc:~/linuxidc.com$ ./linuxidc.com.sh

linuxidc.com

linuxidc.com

linuxidc.com

linuxidc.com

linuxidc.com

time: 2

1f06832da253cb8de6e2f7734f8cb4d9.png

说下改动,首先我把for循环中的代码用{}包为一个块,然后增加&符号使其后台运行,之后增加wait指令,该指令会等待所有后台进程结束,如果不加wait,程序直接往下走,最终打出的time将会是0。现在程序已经由之前的10秒缩短为2秒,似乎效果不错,不过试想这样一个场景,有1000个这样的任务,如果还是以这种方式执行,机器负载是扛不住的,我们必须想一种办法来控制进程的并发数,那就是管道和文件描述符。

首先介绍下管道(pipe):

无名管道

它经常出现在我们的命令中,例如cat /etc/passwd | awk -F: '{print $1}',其中"|"就是管道,它将前一个命令的结果输出到后一个进程中,作为两个进程的数据通道,不过他是无名的。

有名管道

使用mkfifo命令创建的管道即为有名管道,例如,mkfifo pipefile, pipefile即为有名管道。

管道有一个显著的特点,如果管道里没有数据,那么去取管道数据时,程序会阻塞住,直到管道内进入数据,然后读取才会终止这个操作,反之,管道在执行写入操作时,如果没有读取操作,同样会阻塞,下面是实例:

linuxidc@linuxidc:~/linuxidc.com$ mkfifo linuxmi

linuxidc@linuxidc:~/linuxidc.com$ echo www.linuxidc.com > linuxmi

# 此时会阻塞在这

9a85bacb4514be78ccdccd35c3408b37.png

此时我新开一个窗口再执行读操作

linuxidc@linuxidc:~/linuxidc.com$ cat linuxmi

www.linuxidc.com

f50e7f175c5a87dd92d8ed0ffe71bd24.png

这时窗口一中的进程才会终止,再来看先读的情况:

linuxidc@linuxidc:~/linuxidc.com$ cat linuxmi

# 同样阻塞停滞在此

70353956119f71c3b73b3765f9168e71.png

新开窗口执行写操作:

linuxidc@linuxidc:~/linuxidc.com$ echo www.linuxidc.com > linuxmi

497ffa254c2cf18a202c0f1e4bab3795.png

这时窗口一会立刻读出内容并顺利完成

接下来看一下文件描述符

Linux系统在初始运行时,会自动绑定三个文件描述符0 1 2 对应 stdin ,stdout, stderr,在/proc/self/fd可以找到

linuxidc@linuxidc:~/linuxidc.com$ cd /proc/self/fd

linuxidc@linuxidc:/proc/self/fd$ ll

总用量 0

dr-x------ 2 linuxidc linuxidc  0 4月  26 15:35 ./

dr-xr-xr-x 9 linuxidc linuxidc  0 4月  26 15:35 ../

lrwx------ 1 linuxidc linuxidc 64 4月  26 15:35 0 -> /dev/pts/3

lrwx------ 1 linuxidc linuxidc 64 4月  26 15:35 1 -> /dev/pts/3

lrwx------ 1 linuxidc linuxidc 64 4月  26 15:35 2 -> /dev/pts/3

lrwx------ 1 linuxidc linuxidc 64 4月  26 15:35 255 -> /dev/pts/3

# 绑定到我们的终端设备上

linuxidc@linuxidc:/proc/self/fd$ echo linuxidc.com > /proc/self/fd/1

linuxidc.com

linuxidc@linuxidc:/proc/self/fd$ echo linuxidc.com > /proc/self/fd/2

linuxidc.com

36e0af25c83766ab90999b157abfea38.png

输出到几个文件的内容会打印到控制台上

我们可以使用exec 指令自行定义、绑定文件描述符,文件描述符的取值范围是3-(ulimit -n)-1

在我本机这个范围是3-1023

linuxidc@linuxidc:~/linuxidc.com$ ulimit -n

1024

linuxidc@linuxidc:~/linuxidc.com$ exec 1025<>linuxidc

bash: 1025: 错误的文件描述符

linuxidc@linuxidc:~/linuxidc.com$ exec 1022<>linuxidc

下面开始介绍如何使用管道文件和文件描述符来控制进程并发:

mkfifo

exec 5<>linuxidc

rm -f linuxidc

首先创建一个管道文件linuxidc,然后使用exec命令将该文件的输入输出绑定到5号文件描述符,而后删除该管道文件,这里删除的只是该文件的Inode,实际文件已由内核open函数打开,这里删除并不会影响程序执行,当程序执行完后,文件描述符会被系统自动回收。

for ((i=1;i<=10;i++)); do

echo >&5

done

通过一个for循环向该文件描述符写入10个空行,这个10其实就是我们定义的后台进程数量,这里需要注意的是,管道文件的读取是以行为单位的。

for ((j=1;j<=100;j++)); do

read -u5

{

echo test$j

sleep 2

echo >&5

}&

done

wait

这里假定我后台有100个任务,而我们在后台保证只有10个进程在同时运行

read -u5 的作用是,读取5号文件描述符中的一行,就是读取一个空行

在减少文件描述符的一个空行之后,在后台执行一次任务,而任务在执行完成以后,会向文件描述符中再写入一个空行,这是为什么呢,因为如果我们写入空行的话,当后台放入了10个任务之后,由于没有可读取的空行,read -u5就会被阻塞住!

exec 5>&-

exec 5

我们生成做绑定时 可以用 exec 5<>linuxidc 来实现,但关闭时必须分开来写> 读的绑定,< 标识写的绑定 <> 则标识 对文件描述符5的所有操作等同于对管道文件linuxidc的操作。

完整代码如下:

#!/bin/bash

mkfifo linuxidc

exec 5<>linuxidc

rm -f tm1

for ((i=1;i<=10;i++)); do

echo >&5

done

for ((j=1;j<=100;j++)); do

read -u5

{

echo test$j

sleep 2

echo >&5

}&

done

wait

exec 5>&-

exec 5

这样,就实现了进程的并发控制。

0b1331709591d260c1c78e86d0c51c18.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值