shell多进程及限制并发

2020-03-02  本文已影响0人  水平号

shell多进程

shell中实现多进程实际上就是将多个任务放到后台中执行而已

使用 {}&

示例1:

#!/bin/bash

for i in {1..100}
do
        {
        user=tt$i
        useradd $user
        echo "111" |passwd --stdin $user &>/dev/null
        if [ $? -eq 0 ];then
                echo "$user is created."
        fi
        }&
done
wait
echo "finish..."

示例2

#!/bin/bash

for i in {1..254}
do
        {
        ip=192.168.40.$i
        ping -c1 -W1 $ip &>/dev/null
        if [ $? -eq 0 ];then
                echo "$ip is up."
        else
                echo "$ip is down"
        fi
        }&
done
wait
echo "all finish..."

shell中控制多个进程并发执行的方法

需要控制多进程并发的数量该如何实现呢?

shell并发控制需要用到2项技能,1,文件描述符 2,管道

1,文件描述符

File descriptors(FD,文件描述符)或文件句柄:

进程使用文件描述符来管理打开的文件

image.png
Shell>  ll /proc/$$/fd         # $$当前进程打开的文件描述符

total 0
lrwx------. 1 root root 64 Feb 28 09:53 0 -> /dev/pts/1
lrwx------. 1 root root 64 Feb 28 09:53 1 -> /dev/pts/1
lrwx------. 1 root root 64 Feb 28 09:53 2 -> /dev/pts/1
lrwx------. 1 root root 64 Feb 29 21:48 255 -> /dev/pts/1

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

示例1:下面操作说明文件和文件描述符的关系。

Shell> touch /file1       #新文件

Shell>  exec 6<> /file1   #打开一个文件描述符6

Shell>  ll /proc/$$/fd    #查看当前打开的文件描述符
total 0
lrwx------. 1 root root 64 Feb 28 09:53 0 -> /dev/pts/1
lrwx------. 1 root root 64 Feb 28 09:53 1 -> /dev/pts/1
lrwx------. 1 root root 64 Feb 28 09:53 2 -> /dev/pts/1
lrwx------. 1 root root 64 Feb 29 21:48 255 -> /dev/pts/1
lrwx-----. 1 root root 64 Feb 28 09:53 6 -> /file1

Shell>  echo "tianyun" > /proc/$$/fd/6         #添加内容到文件描述符6

Shell>  cat /file1                           #查看file1内是否出现添加的内容
Tianyun 

Shell>  rm -rf /file1                        #删除file1文件

Shell>  ll /proc/$$/fd                      #再查看当前打开的文件描述符(6还在)
total 0
lrwx------. 1 root root 64 Feb 28 09:53 0 -> /dev/pts/1
lrwx------. 1 root root 64 Feb 28 09:53 1 -> /dev/pts/1
lrwx------. 1 root root 64 Feb 28 09:53 2 -> /dev/pts/1
lrwx------. 1 root root 64 Feb 29 21:48 255 -> /dev/pts/1
lrwx------. 1 root root 64 Feb 28 09:53 6 -> /file1 (deleted)

Shell>  cp /proc/$$/fd/6 /file1                   #把文件描述符6复制到file1

Shell>  cat /file1                              #文件内容重新还原
tianyun

Shell>  exec 6<&-                            #删除文件描述符

Shell>  ll /proc/$$/fd
total 0
lrwx------. 1 root root 64 Feb 28 09:53 0 -> /dev/pts/1
lrwx------. 1 root root 64 Feb 28 09:53 1 -> /dev/pts/1
lrwx------. 1 root root 64 Feb 28 09:53 2 -> /dev/pts/1
lrwx------. 1 root root 64 Feb 29 21:48 255 -> /dev/pts/1

如何exec打开一个文件

如何exec关闭一个文件(释放文件句柄)

当一个文件FD末被释放,删除原文件也不会影响FD

2,管道

image.png

一个进程的输出作为 另一个进程的输入

匿名管道

rpm -qa |grep mysql

| 就是管道,管道也是个文件,文件内容采用先进先出,阅(使用)后即焚(被消费),相当消息队列。

命名管道

示例1:说明命名管道可以跨越终端,终端1写入,终端2读出。

Shell>  mkfifo /tmp/tmpfifo        #创建命名管道

shell>  file /tmp/tmpfifo           #查看文件属性

/tmp/tmpfifo: fifo (named pipe)

Shell> tty                                #所在终端

/dev/pts/0

Shell> tty                                #查看所在终端

/dev/pts/1

Shell> grep 'sda' /tmp/tmpfifo               #
brw-rw----. 1 root disk      8,   0 Feb 22 10:01 sda
brw-rw----. 1 root disk      8,   1 Feb 22 10:01 sda1
brw-rw----. 1 root disk      8,   2 Feb 22 10:01 sda2

示例2:利用命名管道限制并发
管道有一个显著的特点,如果管道里没有数据,那么去取管道数据时,程序会阻塞住,直到管道内进入数据,然后读取才会终止这个操作,反之,管道在执行写入操作时,如果没有读取操作,同样会阻塞.

#!/bin/bash

#说明:利用命名管道和文件描述符来限制shell并发。
#初始化5个进程处理,当其中一个进程处理完,就会重新写入1行空行到文件描述符8中,再次读取文件描述符8又可以继续处理,保持同时5个进程在线处理。

thread=5

tmp_fifofile=/tmp/$$.fifo       # $$获取当前PID,由于PID数值随便生成,不容易和其它文件冲突

mkfifo $tmp_fifofile           #创建命名管道文件

exec 8<> $tmp_fifofile         #使用exec命令将该文件的输入输出绑定到8号文件描述符

rm $tmp_fifofile              #而后删除该管道文件,这里删除的只是该文件的Inode,实际文件已由内核open函数打开,这里删除并不会影响程序执行

for i in `seq $thread`          #循环写入5行空行到8号文件描述符
do
        echo >&8         
done

for i in {1..254}
do
        read -u 8          #读取8号文件描述符中的一行,就是读取一个空行
        {
        ip=192.168.40.$i
        ping -c1 -W1 $ip &>/dev/null
        if [ $? -eq 0 ];then
                echo "$ip ip up."
        else
                echo "$ip ip down."
        fi
        echo >&8        #写入1空行到8号文件描述符,这样可以保持同时有5个进程在线

        }&                #for循环中的代码用{}包为一个块,然后增加&符号使其后台运行
done
wait          #增加wait指令,该指令会等待所有后台进程结束
exec 8>&-       #使用完8号文件描述符后关闭,关闭时必须分开来写> 读的绑定,
exec 8<&-      #< 标识写的绑定
echo "all finish..."
image.png

原理:利用命名管道特征(管道有一个显著的特点,如果管道里没有数据,那么去取管道数据时,程序会阻塞住,直到管道内进入数据,然后读取才会终止这个操作,反之,管道在执行写入操作时,如果没有读取操作,同样会阻塞),根据这个特点初始化大小(配置一次性写入行数),并且通过read -u读取管道文件(按行)1行,之后后台执行完会再次写入1行空行到管道文件( echo >&8),如此循环保证后台始终保持一定数量(这个数量由自己决定)进程执行。

可参考其它文章:https://blog.51cto.com/hld1992/2370135

上一篇下一篇

猜你喜欢

热点阅读