如何實現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秒多點。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章