bash多进程
在bash中,使用后臺任務來實現任務的“多進程化”。在不加控制的模式下,不管有多少任務,全部都后臺執行。也就是說,在這種情況下,有多少任務就有多少“進程”在同時執行。我們就先實現第一種情況:
實例一:正常情況腳本
| 1 2 3 4 5 6 7 8 9 10 | #!/bin/bash for ((i=0;i<5;i++));do ???????{ ???????????????sleep 3;echo 1>>aa && echo "done!" ???????} done wait cat aa|wc -l rm aa |
這種情況下,程序順序執行,每個循環3s,共需15s左右。
| 1 2 3 4 5 6 7 8 9 10 11 | $ time bash test.sh done! done! done! done! done! 5 real??? 0m15.030s user??? 0m0.002s sys???? 0m0.003s |
實例二:“多進程”實現
| 1 2 3 4 5 6 7 8 9 10 | #!/bin/bash for ((i=0;i<5;i++));do ????????{ ????????????????sleep 3;echo 1>>aa && echo "done!" ????????} & done wait cat aa|wc -l rm aa |
這個實例實際上就在上面基礎上多加了一個后臺執行&符號,此時應該是5個循環任務并發執行,最后需要3s左右時間。
| 1 2 3 4 5 6 7 8 9 10 11 | $ time bash test.sh done! done! done! done! done! 5 real??? 0m3.011s user??? 0m0.002s sys???? 0m0.004s |
效果非常明顯。
這里需要說明一下wait的左右。wait是等待前面的后臺任務全部完成才往下執行,否則程序本身是不會等待的,這樣對后面依賴前面任務結果的命令來說就可能出錯。例如上面wc -l的命令就報錯:不存在aa這個文件。
wait命令的官方解釋如下:
| 1 2 | wait [n] ???????Wait for the specified process and return its termination status.? n may be a process ID or? a? job? specification; if a job spec is given, all processes in that job's pipeline are waited for.? If n is not given, all currently active child processes are waited for, and the return status is zero.? If? n? specifies? a? non-existent process? or job, the return status is 127.? Otherwise, the return status is the exit status of the last processor job waited for. |
以上所講的實例都是進程數目不可控制的情況,下面描述如何準確控制并發的進程數目。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | #!/bin/bash # 2006-7-12, by wwy #----------------------------------------------------------------------------------- # 此例子說明了一種用wait、read命令模擬多線程的一種技巧 # 此技巧往往用于多主機檢查,比如ssh登錄、ping等等這種單進程比較慢而不耗費cpu的情況 # 還說明了多線程的控制 #----------------------------------------------------------------------------------- function a_sub { # 此處定義一個函數,作為一個線程(子進程) sleep 3 # 線程的作用是sleep 3s } tmp_fifofile="/tmp/$$.fifo" mkfifo $tmp_fifofile????? # 新建一個fifo類型的文件 exec 6<>$tmp_fifofile????? # 將fd6指向fifo類型 rm $tmp_fifofile thread=15 # 此處定義線程數 for ((i=0;i<$thread;i++));do echo done >&6 # 事實上就是在fd6中放置了$thread個回車符 for ((i=0;i<50;i++));do # 50次循環,可以理解為50個主機,或其他 read -u6 # 一個read -u6命令執行一次,就從fd6中減去一個回車符,然后向下執行, # fd6中沒有回車符的時候,就停在這了,從而實現了線程數量控制 { # 此處子進程開始執行,被放到后臺 ??????a_sub && { # 此處可以用來判斷子進程的邏輯 ???????echo "a_sub is finished" ??????} || { ???????echo "sub error" ??????} ??????echo >&6 # 當進程結束以后,再向fd6中加上一個回車符,即補上了read -u6減去的那個 } & done wait # 等待所有的后臺子進程結束 exec 6>&- # 關閉df6 exit 0 |
結束任務:
| 1 | pstree -ap 3471|grep -oP '[0-9]{3,6}'|xargs kill -9 |
sleep 3s,線程數為15,一共循環50次,所以,此腳本一共的執行時間大約為12秒
即:
| 1 2 3 4 5 6 7 8 9 | 15x3=45, 所以 3 x 3s = 9s (50-45=5)<15, 所以 1 x 3s = 3s 所以 9s + 3s = 12s $ time ./multithread.sh >/dev/null real??????? 0m12.025s user??????? 0m0.020s sys???????? 0m0.064s |
而當不使用多線程技巧的時候,執行時間為:50 x 3s = 150s。
此程序中的命令
| 1 | mkfifo tmpfile |
和linux中的命令
| 1 | mknod tmpfile p |
效果相同。區別是mkfifo為POSIX標準,因此推薦使用它。該命令創建了一個先入先出的管道文件,并為其分配文件標志符6。管道文件是進程之間通信的一種方式,注意這一句很重要
| 1 | exec 6<>$tmp_fifofile????? # 將fd6指向fifo類型 |
如果沒有這句,在向文件$tmp_fifofile或者&6寫入數據時,程序會被阻塞,直到有read讀出了管道文件中的數據為止。而執行了上面這一句后就可以在程序運行期間不斷向fifo類型的文件寫入數據而不會阻塞,并且數據會被保存下來以供read程序讀出。
原文:http://www.cnitblog.com/sysop/archive/2008/11/03/50974.aspx
總結
- 上一篇: 计算机网络-数据链路层
- 下一篇: centos7 安装、使用git