當前位置:
首頁 > 最新 > 深入Python多進程通信原理與實戰——圖文

深入Python多進程通信原理與實戰——圖文

繼上節使用原生多進程並行運行,基於Redis作為消息隊列完成了圓周率的計算,本節我們使用原生操作系統消息隊列來替換Redis。


文件

使用文件進行通信是最簡單的一種通信方式,子進程將結果輸出到臨時文件,父進程從文件中讀出來。文件名使用子進程的進程id來命名。進程隨時都可以通過來獲取自己的進程id。

輸出

管道pipe

管道是Unix進程間通信最常用的方法之一,它通過在父子進程之間開通讀寫通道來進行雙工交流。我們通過os.read()和os.write()來對文件描述符進行讀寫操作,使用os.close()關閉描述符。

上圖為單進程的管道

上圖為父子進程分離後的管道

輸出


我們知道跨網路通信免不了要通過套接字進行通信,但是本例的多進程是在同一個機器上,用不著跨網路,使用普通套接字進行通信有點浪費。

上圖為單進程的socketpair

上圖為父子進程分離後的socketpair

為了解決這個問題,Unix系統提供了無名套接字socketpair,不需要埠也可以創建套接字,父子進程通過socketpair來進行全雙工通信。

socketpair返回兩個套接字對象,一個用於讀一個用於寫,它有點類似於pipe,只不過pipe返回的是兩個文件描述符,都是整數。所以寫起代碼形式上跟pipe幾乎沒有什麼區別。

我們使用sock.send()和sock.recv()來對套接字進行讀寫,通過sock.close()來關閉套接字對象。

輸出


操作系統也提供了跨進程的消息隊列對象可以讓我們直接使用,只不過python沒有默認提供包裝好的api來直接使用。我們必須使用第三方擴展來完成OS消息隊列通信。第三方擴展是通過使用Python包裝的C實現來完成的。

OS消息隊列有兩種形式,一種是posix消息隊列,另一種是systemv消息隊列,有些操作系統兩者都支持,有些只支持其中的一個,比如macos僅支持systemv消息隊列,我本地的python的docker鏡像是debian linux,它僅支持posix消息隊列。

posix消息隊列

我們先使用posix消息隊列來完成圓周率的計算,posix消息隊列需要提供一個唯一的名稱,它必須是開頭。close()方法僅僅是減少內核消息隊列對象的引用,而不是徹底關閉它。unlink()方法才能徹底銷毀它。O_CREAT選項表示如果不存在就創建。向隊列里塞消息使用send方法,收取消息使用receive方法,receive方法返回一個tuple,tuple的第一個值是消息的內容,第二個值是消息的優先順序。之所以有優先順序,是因為posix消息隊列支持消息的排序,在send方法的第二個參數可以提供優先順序整數值,默認為0,越大優先順序越高。

輸出

systemv消息隊列

systemv消息隊列和posix消息隊列用起來有所不同。systemv的消息隊列是以整數key作為名稱,如果不指定,它就創建一個唯一的未佔用的整數key。它還提供消息類型的整數參數,但是不支持消息優先順序。

輸出


共享內存也是非常常見的多進程通信方式,操作系統負責將同一份物理地址的內存映射到多個進程的不同的虛擬地址空間中。進而每個進程都可以操作這份內存。考慮到物理內存的唯一性,它屬於臨界區資源,需要在進程訪問時搞好並發控制,比如使用信號量。我們通過一個信號量來控制所有子進程的順序讀寫共享內存。我們分配一個8位元組double類型的共享內存用來存儲極限的和,每次從共享內存中讀出來時,要使用struct進行反序列化(unpack),將新的值寫進去之前也要使用struct進行序列化(pack)。每次讀寫操作都需要將讀寫指針移動到內存開頭位置(lseek)。

輸出


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 Python 的精彩文章:

Python面試攻略
Python黑客不得不提的三個滲透腳本,我卻偷偷曝光是不是不厚道?

TAG:Python |