首先我把for循环中的代码用{}包为一个块,然后增加&符号使其后台运行,之后增加wait指令,该指令会等待所有后台进程结束,如果不加wait,程序直接往下走,最终打出的time将会是0。现在程序已经由之前的10秒缩短为2秒,似乎效果不错,不过试想这样一个场景,有1000个这样的任务,如果还是以这种方式执行,机器负载是扛不住的,我们必须想一种办法来控制进程的并发数,那就是管道和文件描述符。
首先介绍下管道(pipe):
管道有一个显著的特点,如果管道里没有数据,那么去取管道数据时,程序会阻塞住,直到管道内进入数据,然后读取才会终止这个操作,反之,管道在执行写入操作时,如果没有读取操作,同样会阻塞。
#ping01 #!/usr/bin/bash thread=5#进程数量 tmp_fifofile=/tmp/$$.fifo mkfifo $tmp_fifofile exec 8<> $tmp_fifofile rm $tmp_fifofile ##描述符8还存在,是否删除tmp_fifofile对fd=8没有影响 for i in `seq $thread` do ##这里用>>追加是没有意义的,因为这是管道,不是常规文件,所以这里不可能会覆盖前面的内容的,后面 ##增加的内容对前面没有影响 echo >&8 ##&8指的就是文件描述符8,单个echo就是回车。echo "111" > &8 ##该文件tmp_fifofile里面有5个回车 done for i in {2..254} do ##read --help,-u跟文件描述符 ##读一个回车,就循环,循环到第6次的时候,就跳出read了,因为没得读了 ##read会将管道中的5个空格都读完,读完才跳出read,但是每次读完一个空格又给管道塞一个空格 read -u 8 { ip=192.168.122.$i ping -c1 -W1 $ip &>/dev/null ## -W1表示1秒超时 if [ $? -eq 0 ];then echo "$ip is up" else echo "$ip is down" fi echo >&8 ##上面的事做完了,就还回去。不要都借完了,再还回去,保证管道的输入有5个数据输入 }& done wait ##等待所有的后台进程执行结束,如果不加这里,有些ping执行不成功,就会执行echo "finish" exec 8>&- exex 8<&- #生成做绑定时 可以用 exec 8<>tmp_fifofile 来实现,但关闭时必须分开来写> 读的绑定,< 标识写的绑定 <> 则标识 对文件描述符8的所有操作等同于对管道文件tm1的操作 echo "finish"