如何实现shell并发

很多人都问我如何写shell脚本,如何实现同时给三台ftp服务器上传文件,如何同时检测三台服务器是否alive等,其实这就是想实现shell的并发。那么shell并发该如何实现呢?

    下面我就拿这个例子来讲:


    每次任务都是输出字符“bingfa”,并停留一秒钟,共20次。


    按照正常思维,脚本应该这样写:


  1. [root@station1 ~]# cat a.sh

  2. #!/bin/bash

  3. for((i=0;i<20;i++))

  4. do

  5. sleep 1

  6. echo "bingfa"

  7. done

  8. [root@station1 ~]# time bash a.sh

  9. bingfa

  10. bingfa

  11. bingfa

  12. bingfa

  13. bingfa

  14. bingfa

  15. bingfa

  16. bingfa

  17. bingfa

  18. bingfa

  19. bingfa

  20. bingfa

  21. bingfa

  22. bingfa

  23. bingfa

  24. bingfa

  25. bingfa

  26. bingfa

  27. bingfa

  28. bingfa


  29. real 0m20.067s

  30. user 0m0.016s

  31. sys 0m0.031s

  32. [root@station1 ~]#

可以看到执行此脚本大概用了20秒。那么使用shell并发该怎么写,很多人都会想到后台程序,类似如下:


  1. [root@station1 ~]# cat b.sh

  2. #!/bin/bash

  3. for((i=0;i<20;i++))

  4. do

  5. {

  6. sleep 1

  7. echo "bingfa"

  8. }&

  9. done

  10. wait

  11. [root@station1 ~]# time bash b.sh

  12. bingfa

  13. bingfa

  14. bingfa

  15. bingfa

  16. bingfa

  17. bingfa

  18. bingfa

  19. bingfa

  20. bingfa

  21. bingfa

  22. bingfa

  23. bingfa

  24. bingfa

  25. bingfa

  26. bingfa

  27. bingfa

  28. bingfa

  29. bingfa

  30. bingfa

  31. bingfa


  32. real 0m1.060s

  33. user 0m0.005s

  34. sys 0m0.057s

  35. [root@station1 ~]#


这样写只需花大概一秒钟,可以看到所有的任务几乎同时执行,如果任务量非常大,系统肯定承受不了,也会影响系统中其他程序的运行,这样就需要一个线程数量的控制。下面是我一开始写的代码(是有问题的):


  1. [root@station1 ~]# cat c.sh

  2. #!/bin/bash

  3. exec 6<>tmpfile

  4. echo "1\n1\n1" &>6

  5. for((i=0;i<20;i++))

  6. do

  7. read -u 6

  8. {

  9. sleep 1

  10. echo "$REPLY"

  11. echo "1" 1>&6

  12. }&

  13. done

  14. wait

  15. [root@station1 ~]# time bash c.sh

  16. 111

  17. 1

  18. 1

  19. 1

  20. 1

  21. 1

  22. 1

  23. 1

  24. 1

  25. 1

  26. 1

  27. 1

  28. 1

  29. 1

  30. 1

  31. 1

  32. 1

  33. 1

  34. 1

  35. 1


  36. real 0m1.074s

  37. user 0m0.012s

  38. sys 0m0.031s

  39. [root@station1 ~]#


可以明显看出是有问题的,我本想控制线程个数为3,但是就算文件描述符6中为空,也会被读取空,然后跳过继续下面的执行,所以使用文件描述符打开一个文件是不行的,然后我就想着使用类似管道的文件来做,下面是我的代码:


  1. [root@station1 ~]# cat d.sh

  2. #!/bin/bash

  3. mkfifo fd2

  4. exec 9<>fd2

  5. echo -n -e "1\n1\n1\n" 1>&9


  6. for((i=0;i<20;i++))

  7. do

  8. read -u 9

  9. { #your process


  10. sleep 1

  11. echo "$REPLY"

  12. echo -ne "1\n" 1>&9

  13. } &

  14. done

  15. wait

  16. rm -f fd2

  17. [root@station1 ~]# time bash d.sh

  18. 1

  19. 1

  20. 1

  21. 1

  22. 1

  23. 1

  24. 1

  25. 1

  26. 1

  27. 1

  28. 1

  29. 1

  30. 1

  31. 1

  32. 1

  33. 1

  34. 1

  35. 1

  36. 1

  37. 1


  38. real 0m7.075s

  39. user 0m0.018s

  40. sys 0m0.044s

  41. [root@station1 ~]#

这样就ok了,三个线程运行20个任务,7秒多点。


你可能感兴趣的:(并发,shell)