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.pngShell> 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),如此循环保证后台始终保持一定数量(这个数量由自己决定)进程执行。
网友评论