shell的多進程

來源:互聯網
上載者:User

標籤:後台運行   處理器   程式   多線程   管道   

650) this.width=650;" src="/e/u261/themes/default/images/spacer.gif" style="background:url("/e/u261/lang/zh-cn/images/localimage.png") no-repeat center;border:1px solid #ddd;" alt="spacer.gif" />650) this.width=650;" src="http://s3.51cto.com/wyfs02/M00/51/41/wKiom1RjDWTRg8_iAACibsrFrF8897.jpg" title="1.png" alt="wKiom1RjDWTRg8_iAACibsrFrF8897.jpg" />

看執行結果:

650) this.width=650;" src="/e/u261/themes/default/images/spacer.gif" style="background:url("/e/u261/lang/zh-cn/images/localimage.png") no-repeat center;border:1px solid #ddd;" alt="spacer.gif" />650) this.width=650;" src="http://s3.51cto.com/wyfs02/M00/51/3F/wKioL1RjDeDDSJJZAABcageVZug821.jpg" title="2.png" alt="wKioL1RjDeDDSJJZAABcageVZug821.jpg" />

很明顯是8s

=============================

這種不佔處理器卻有很耗時的進程,我們可以通過一種後台啟動並執行方式

來達到節約時間的目的。看如下改進:

650) this.width=650;" src="/e/u261/themes/default/images/spacer.gif" style="background:url("/e/u261/lang/zh-cn/images/localimage.png") no-repeat center;border:1px solid #ddd;" alt="spacer.gif" />650) this.width=650;" src="http://s3.51cto.com/wyfs02/M01/51/41/wKiom1RjDYKy0e7fAADYls6W8oU881.jpg" title="3.png" alt="wKiom1RjDYKy0e7fAADYls6W8oU881.jpg" />

用“{}”將主執行程式變為一個塊,用&放入後台,四次執行全部放入後台後,我們

需要用一個wait指令,等待所有後台進程執行結束,

不然 系統是不會等待的,直接繼續執行後續指令,知道整個程式結束。

看結果:

650) this.width=650;" src="/e/u261/themes/default/images/spacer.gif" style="background:url("/e/u261/lang/zh-cn/images/localimage.png") no-repeat center;border:1px solid #ddd;" alt="spacer.gif" />650) this.width=650;" src="http://s3.51cto.com/wyfs02/M02/51/41/wKiom1RjDZWSsci0AAB8Xdhis2g154.jpg" title="4.png" alt="wKiom1RjDZWSsci0AAB8Xdhis2g154.jpg" />

可以看到,時間已經大大縮短了!

============================

以上實驗雖然達到了多線程並發的目的,但有一個缺陷,不能控制

運行在背景進程數。

為了控制進程,我們引入了管道 和檔案操作符。

無名管道: 就是我們經常使用的 例如: cat text | grep "abc" 

那個“|”就是管道,只不過是無名的,可以直接作為兩個進程的資料通道

有名管道: mkfilo  可以建立一個管道檔案 ,例如: mkfifo fifo_file

 

管道有一個特點,如果管道中沒有資料,那麼取管道資料的操作就會停滯,直到

管道內進入資料,然後讀出後才會終止這一操作,同理,寫入管道的操作

如果沒有讀取操作,這一個動作也會停滯。

650) this.width=650;" src="/e/u261/themes/default/images/spacer.gif" style="background:url("/e/u261/lang/zh-cn/images/localimage.png") no-repeat center;border:1px solid #ddd;" alt="spacer.gif" />650) this.width=650;" src="http://s3.51cto.com/wyfs02/M02/51/3F/wKioL1RjDhSCsIfXAABjOdvRLD4004.jpg" title="5.png" alt="wKioL1RjDhSCsIfXAABjOdvRLD4004.jpg" />

當我們試圖用echo想管道檔案中寫入資料時,由於沒有任何進程在對它做讀取操作,所以

它會一直停留在那裡等待讀取操作,此時我們在另一終端上用cat指令做讀取操作

650) this.width=650;" src="/e/u261/themes/default/images/spacer.gif" style="background:url("/e/u261/lang/zh-cn/images/localimage.png") no-repeat center;border:1px solid #ddd;" alt="spacer.gif" />650) this.width=650;" src="http://s3.51cto.com/wyfs02/M01/51/3F/wKioL1RjDieTeDAAAACaUgamBvs448.jpg" title="6.png" alt="wKioL1RjDieTeDAAAACaUgamBvs448.jpg" />

你會發現讀取操作一旦執行,寫入操作就可以順利完成了,同理,先做讀取操作也是一樣的:

650) this.width=650;" src="/e/u261/themes/default/images/spacer.gif" style="background:url("/e/u261/lang/zh-cn/images/localimage.png") no-repeat center;border:1px solid #ddd;" alt="spacer.gif" />650) this.width=650;" src="http://s3.51cto.com/wyfs02/M01/51/41/wKiom1RjDdCgJvj-AABS2fQMJ8I213.jpg" title="7.png" alt="wKiom1RjDdCgJvj-AABS2fQMJ8I213.jpg" />

由於沒有管道內沒有資料,所以讀取操作一直滯留在那裡等待寫入的資料

650) this.width=650;" src="/e/u261/themes/default/images/spacer.gif" style="background:url("/e/u261/lang/zh-cn/images/localimage.png") no-repeat center;border:1px solid #ddd;" alt="spacer.gif" />650) this.width=650;" src="http://s3.51cto.com/wyfs02/M02/51/41/wKiom1RjDeiRUD6LAAC6gm8vLy8443.jpg" title="8.png" alt="wKiom1RjDeiRUD6LAAC6gm8vLy8443.jpg" />

一旦有了寫入的資料,讀取操作立刻順利完成

以上實驗,看以看到,僅僅一個管道檔案似乎很難實現 我們的目的(控制後台線程數),

所以 接下來介紹 檔案操作符,這裡只做簡單的介紹,如果不熟悉的可以自行查閱資料。

系統運行起始,就相應裝置自動綁定到了 三個檔案操作符   分別為 0 1 2 對應 stdin ,stdout, stderr 。

在 /proc/self/fd 中 可以看到 這三個三個對應檔案

650) this.width=650;" src="/e/u261/themes/default/images/spacer.gif" style="background:url("/e/u261/lang/zh-cn/images/localimage.png") no-repeat center;border:1px solid #ddd;" alt="spacer.gif" />650) this.width=650;" src="http://s3.51cto.com/wyfs02/M02/51/41/wKiom1RjDfWA3CgPAADH8C2ud4A144.jpg" title="9.png" alt="wKiom1RjDfWA3CgPAADH8C2ud4A144.jpg" />

輸出到這三個檔案的內容都會顯示出來。只是因為顯示器作為最常用的輸出裝置而被綁定。

我們可以exec 指令自行定義、繫結檔案操作符

檔案操作符一般從3-(n-1)都可以隨便使用

此處的n 為 ulimit -n 的定義值得

650) this.width=650;" src="/e/u261/themes/default/images/spacer.gif" style="background:url("/e/u261/lang/zh-cn/images/localimage.png") no-repeat center;border:1px solid #ddd;" alt="spacer.gif" />650) this.width=650;" src="http://s3.51cto.com/wyfs02/M02/51/43/wKiom1RjEdfAMKxrAAEUlGu7SCg650.jpg" title="10.png" alt="wKiom1RjEdfAMKxrAAEUlGu7SCg650.jpg" />

可以看到 我的 n值為1024 ,所以檔案操作符只能使用 0-1023,可自行定義的 就只能是 3-1023 了。

直接上代碼,然後根據程式碼分析每行代碼的含義:

650) this.width=650;" src="/e/u261/themes/default/images/spacer.gif" style="background:url("/e/u261/lang/zh-cn/images/localimage.png") no-repeat center;border:1px solid #ddd;" alt="spacer.gif" />650) this.width=650;" src="http://s3.51cto.com/wyfs02/M02/51/42/wKioL1RjEfCDp8tQAAHP-VZS6uE440.jpg" title="1.png" alt="wKioL1RjEfCDp8tQAAHP-VZS6uE440.jpg" />

第3行:   接受訊號 2 (ctrl +C)做的操作

          exec 1000>&-和exec 1000<&- 是關閉fd1000的意思

          產生做綁定時 可以用 exec 1000<>testfifo 來實現,但關閉時必須分開來寫

          > 讀的綁定,< 標識寫的綁定  <> 則標識 對檔案描述符 1000的所有操作等同於對管道檔案           testfifo的操作。


第5-7行: 分別為 建立管道檔案,檔案操作符綁定,刪除管道檔案

      可能會有疑問,為什麼不能直接使用管道檔案呢? 

      事實上,這並非多此一舉,剛才已經說明了管道檔案的一個重要特性了,那就是讀寫必須同           時存在,缺少某一種操作,另一種操作就是滯留,而繫結檔案操作符 正好解決了這個問題。(至於為什麼,我還沒研究明白,有知道的 還請告知,謝謝)


第9-12 行:    對檔案操作符進行寫入操作。 通過一個for迴圈寫入10個空行,這個10就是我們要定義的後台線程數量。

               為什麼寫入空行而不是10個字元呢 ?

               這是因為,管道檔案的讀取 是以行為單位的。

                      650) this.width=650;" src="/e/u261/themes/default/images/spacer.gif" style="background:url("/e/u261/lang/zh-cn/images/localimage.png") no-repeat center;border:1px solid #ddd;" alt="spacer.gif" /> 650) this.width=650;" src="http://s3.51cto.com/wyfs02/M02/51/43/wKiom1RjEZ7TOWVGAACtN4e607g717.jpg" title="2.png" alt="wKiom1RjEZ7TOWVGAACtN4e607g717.jpg" /> 

              當我們試圖用 read 讀取管道中的一個字元時,結果是不成功的,而剛才我們已經證實               使用cat是可以讀取的。

第17-24行:  這裡假定我們有100個任務,我們要實現的時 ,保證後台只有10個進程在同步運行 。

             read -u1000 的作用是:讀取一次管道中的一行,在這兒就是讀取一個空行。

             減少操作附中的一個空行之後,執行一次任務(當然是放到後台執行),需要注意的是,              這個任務在後台執行結束以後會向檔案操作符中寫入一個空行,這就是重點所在,如果我們不在某種情況某種時刻向操作符中寫入空行,那麼結果就是:

             在後台放入10個任務之後,由於操作符中沒有可讀取的空行,導致  read - u1000 這兒              始終停頓。後邊的 就不用解釋了,貼下執行結果:

650) this.width=650;" src="/e/u261/themes/default/images/spacer.gif" style="background:url("/e/u261/lang/zh-cn/images/localimage.png") no-repeat center;border:1px solid #ddd;" alt="spacer.gif" />650) this.width=650;" src="http://s3.51cto.com/wyfs02/M01/51/42/wKioL1RjEhfxBIqAAAMLTdSjNDw507.jpg" title="3.png" alt="wKioL1RjEhfxBIqAAAMLTdSjNDw507.jpg" />

每次的停頓中都能看到  只有10個進程在運行

一共耗時50s  

一共100個任務,每次10個 ,每個5s 正好50s

上邊的結果圖之所以這麼有規律,這是因為我們所執行的100個任務耗時都是相同的,

比如,系統將第一批10個任務放入背景過程所消耗的時間 幾乎可以忽略不計,也就是說

這10個任務幾乎可以任務是同時運行,當然也就可以認為是同時結束了,而按照剛才的分析,

一個任務結束時就會向檔案描述符寫入空行,既然是同時結束的,那麼肯定是同時寫入的空行,

所以下一批任務又幾乎同時運行,如此迴圈下去的。

實際應用時,肯定不是這個樣子的,比如,第一個放到後台執行的任務,是最耗時間的,

那他肯定就會是最後一個執行完畢。

所以,實際上來說,只要有一個任務完成,那麼下一個任務就可以被放到後台並發執行了。


本文出自 “逆行者” 部落格,請務必保留此出處http://lydygly.blog.51cto.com/2837715/1575730

shell的多進程

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.