Python multiprocessing 使用手記 – 跨進(jìn)程對象共享

轉(zhuǎn)自張聰?shù)腷log

繼續(xù)寫關(guān)于Python multiprocessing的使用手記,繼上次的進(jìn)程模型之后泊交,這次展開討論一下multiprocessing當(dāng)中的跨進(jìn)程對象共享的問題雁歌。

在mp庫當(dāng)中宏浩,跨進(jìn)程對象共享有三種方式,第一種僅適用于原生機器類型靠瞎,即python.ctypes當(dāng)中的類型比庄,這種在mp庫的文檔當(dāng)中稱為shared memory方式,即通過共享內(nèi)存共享對象乏盐;另外一種稱之為server process佳窑,即有一個服務(wù)器進(jìn)程負(fù)責(zé)維護(hù)所有的對象,而其他進(jìn)程連接到該進(jìn)程父能,通過代理對象操作服務(wù)器進(jìn)程當(dāng)中的對象神凑;最后一種在mp文檔當(dāng)中沒有單獨提出,但是在其中多次提到法竞,而且是mp庫當(dāng)中最重要的一種共享方式耙厚,稱為inheritance强挫,即繼承,對象在父進(jìn)程當(dāng)中創(chuàng)建薛躬,然后在父進(jìn)程是通過multiprocessing.Process創(chuàng)建子進(jìn)程之后俯渤,子進(jìn)程自動繼承了父進(jìn)程當(dāng)中的對象,并且子進(jìn)程對這些對象的操作都是反映到了同一個對象型宝。

這三者共享方式各有特色八匠,在這里進(jìn)行一些簡單的比較。

首先是共享方式所應(yīng)對的對象類型趴酣,看這個表:

共享方式 支持的類型
Shared memory ctypes當(dāng)中的類型梨树,通過RawValue,RawArray等包裝類提供
Inheritance 系統(tǒng)內(nèi)核對象岖寞,以及基于這些對象實現(xiàn)的對象抡四。包括Pipe, Queue, JoinableQueue, 同步對象(Semaphore, Lock, RLock, Condition, Event等等)
Server process 所有對象,可能需要自己手工提供代理對象(Proxy)

這個表總結(jié)了三種不同的共享方式所支持的類型仗谆,下面一個個展開討論指巡。

其中最單純簡單的就是shared memory這種方式,只有ctypes當(dāng)中的數(shù)據(jù)類型可以通過這種方式共享隶垮。由于mp庫本身缺少命名的機制藻雪,即在一個進(jìn)程當(dāng)中創(chuàng)建的對象,無法在另外一個進(jìn)程當(dāng)中通過名字來引用狸吞,因此勉耀,這種共享方式依賴于繼承,對象應(yīng)該由父進(jìn)程創(chuàng)建蹋偏,然后由子進(jìn)程引用便斥。關(guān)于這種機制的例子,可以參見Python文檔當(dāng)中的例子 Synchronization types like locks, conditions and queues暖侨,參考其中的test_sharedvalues函數(shù)椭住。

然后是繼承方式崇渗。首先關(guān)于繼承方式需要有說明字逗,繼承本質(zhì)上并不是一種對象共享的機制,對象共享只是其副作用宅广。子進(jìn)程從父進(jìn)程繼承來的對象并不一定是共享的葫掉。繼承本質(zhì)上是父進(jìn)程fork出的子進(jìn)程自動繼承父進(jìn)程的內(nèi)存狀態(tài)和對象描述符。因此跟狱,實際上子進(jìn)程復(fù)制了一份父進(jìn)程的對象俭厚,只不過,當(dāng)這個對象包裝了一些系統(tǒng)內(nèi)核對象的描述符的時候驶臊,拷貝這個對象(及其包裝的描述符)實現(xiàn)了對象的共享挪挤。因此叼丑,在上面的表當(dāng)中,只有系統(tǒng)內(nèi)核對象扛门,和基于這些對象實現(xiàn)的對象鸠信,才能夠通過繼承來共享。通過繼承共享的對象在linux平臺上沒有任何限制论寨,但是在Windows上面由于沒有fork的實現(xiàn)星立,因此有一些額外的限制條件,因此葬凳,在Windows上面绰垂,繼承方式是幾乎無法用的。

最后就是Server Process這種方式火焰。這種方式可以支持的類型比另外兩種都多劲装,因為其模型是這樣的:

server process模型

在這個模型當(dāng)中,有一個manager進(jìn)程昌简,負(fù)責(zé)管理實際的對象酱畅。真正的對象也是在manager進(jìn)程的內(nèi)存空間當(dāng)中。所有需要訪問該對象的進(jìn)程都需要先連接到該管理進(jìn)程江场,然后獲取到對象的一個代理對象(Proxy object)纺酸,通常情況下,這個代理對象提供了實際對象的公共函數(shù)的代理址否,將函數(shù)參數(shù)進(jìn)行pickle餐蔬,然后通過連接傳送到管理進(jìn)程當(dāng)中,管理進(jìn)程將參數(shù)unpickle之后佑附,轉(zhuǎn)發(fā)給相應(yīng)的實際對象的函數(shù)樊诺,返回值(或者異常)同樣經(jīng)過管理進(jìn)程pickle之后,通過連接傳回到客戶進(jìn)程音同,再由proxy對象進(jìn)行unpickle词爬,返回給調(diào)用者或者拋出異常。

很明顯权均,這個模型是一個典型的RPC(遠(yuǎn)程過程調(diào)用)的模型顿膨。因為每個客戶進(jìn)程實際上都是在訪問manager進(jìn)程當(dāng)中的對象,因此完全可以通過這個實現(xiàn)對象共享叽赊。

manager和proxy之間的連接可以是基于socket的網(wǎng)絡(luò)連接恋沃,也可以是unix pipe。如果是使用基于socket的連接方式必指,在使用proxy之前囊咏,需要調(diào)用manager對象的connect函數(shù)與遠(yuǎn)程的manager進(jìn)程建立連接。由于manager進(jìn)程會打開端口接收該連接,因此必要的身份驗證是需要的梅割,否則任何人都可以連上manager弄亂你的共享對象霜第。mp庫通過authkey的方式來進(jìn)行身份驗證。

在實現(xiàn)當(dāng)中户辞,manager進(jìn)程通過multiprocessing.Manager類或者BaseManager的子類實現(xiàn)庶诡。BaseManager提供了函數(shù)register注冊一個函數(shù)來獲取共享對象的proxy。這個函數(shù)會被客戶進(jìn)程調(diào)用咆课,然后在manager進(jìn)程當(dāng)中執(zhí)行末誓。這個函數(shù)可以返回一個共享的對象(對所有的調(diào)用返回同一個對象),或者可以為每一個調(diào)用創(chuàng)建一個新的對象书蚪,通過前者就可以實現(xiàn)多個進(jìn)程共享一個對象喇澡。關(guān)于這個的用法可以參考Python文檔當(dāng)中的例子“Demonstration of how to create and use customized managers and proxies”。

典型的導(dǎo)出一個共享對象的代碼是:

|

<pre class="python" style="margin: 0px; padding: 0px; background: none; border: none; width: auto; float: none; clear: none; overflow: visible; font-size: 12px; line-height: 1.333; font-family: monospace;">ObjectType object_

class

ObjectManager

(

multiprocessing.

managers

.

BaseManager

)

:

pass

ObjectManager.

register

(

"object"

,

lambda

: object_

)

</pre>

|

注意上面介紹proxy對象的時候殊校,我提到的“公共函數(shù)”四個字晴玖。每個proxy對象只會導(dǎo)出實際對象的公共函數(shù)。這里面有兩個含義为流,一個是“公共”呕屎,即所有非下劃線開頭的成員,另一個是“函數(shù)”敬察,即所有callable的成員秀睛。這就帶來一些限制,一是無法導(dǎo)出屬性莲祸,二是無法導(dǎo)出一些公共的特殊函數(shù)蹂安,例如get, next等等。對于這個mp庫有一套處理锐帜,即自定義proxy對象田盈。首先是BaseManager的register可以提供一個proxy_type作為第三個參數(shù),這個參數(shù)指定了哪些成員需要被導(dǎo)出缴阎。詳細(xì)的使用方法可以參見文檔當(dāng)中的第一個例子允瞧。

另外manager還有一些細(xì)節(jié)的問題需要注意。由于Proxy對象不是線程安全的蛮拔,因此如果需要在一個多線程程序當(dāng)中使用proxy述暂,mp庫會為每個線程創(chuàng)建一個proxy對象,而每個proxy對象都會對server process創(chuàng)建一個連接语泽,而manager那邊對于每個連接都創(chuàng)建一個單獨的線程來為其服務(wù)贸典。這樣帶來的問題就是,如果客戶進(jìn)程有很多線程踱卵,很容易會導(dǎo)致manager進(jìn)程的fd數(shù)目達(dá)到ulimit的限制,即使沒有達(dá)到限制,也會因為manager進(jìn)程當(dāng)中有太多線程而嚴(yán)重影響manager的性能惋砂。解決方案可以是一個進(jìn)程內(nèi)cache妒挎,只有一個單獨的線程可以創(chuàng)建proxy對象訪問共享對象,其余線程只能訪問該進(jìn)程當(dāng)中的cache西饵。

一旦manager因為達(dá)到ulimit限制或者其他異常酝掩,manager會直接退出,遺憾的是眷柔,這時候已經(jīng)建立的proxy會試圖重新連接manager – 但是它已經(jīng)不存在了期虾。這個會導(dǎo)致客戶進(jìn)程hang在對proxy的函數(shù)調(diào)用上,這個時候驯嘱,目前除了殺掉進(jìn)程沒有找到別的辦法镶苞。

另外proxy使用socket的方式比較tricky,因此和內(nèi)置的socket庫有很多沖突鞠评,比如socket.setdefaulttimeout(Python Issue 6056

)茂蚓。在setdefaulttimeout調(diào)用了之后,進(jìn)程當(dāng)中所有通過socket模塊建立的socket都是被設(shè)置為unblock模式的剃幌,但是mp庫并不知道這一點聋涨,而且它總是假設(shè)socket都是block模式的,于是负乡,一旦調(diào)用了setdefaulttimeout牍白,所有對于proxy的函數(shù)調(diào)用都會拋出OSError,錯誤代碼為11抖棘,錯誤原因是非常有誤導(dǎo)性的“Resource temporarily unavailable”淹朋,實際上就是EAGAIN。這個錯誤可以通過我提供的一個patch來補救(這個patch當(dāng)中還包含其他的一些修復(fù)钉答,所以請自行查看并修改該patch)础芍。

由于以上的一些原因,server process模式作為一個對象的共享模式数尿,能夠提供最為靈活的共享方式仑性,但是也有最多的問題。這個在使用過程當(dāng)中就靠自己去衡量了右蹦。目前我們的系統(tǒng)對于數(shù)據(jù)可靠性方面要求不高诊杆,丟失數(shù)據(jù)是可以接受的,但是也只用這種模式來維護(hù)統(tǒng)計值何陆,不敢用來維護(hù)更多的東西晨汹。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市贷盲,隨后出現(xiàn)的幾起案子淘这,更是在濱河造成了極大的恐慌剥扣,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件铝穷,死亡現(xiàn)場離奇詭異钠怯,居然都是意外死亡,警方通過查閱死者的電腦和手機曙聂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進(jìn)店門晦炊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人宁脊,你說我怎么就攤上這事断国。” “怎么了榆苞?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵稳衬,是天一觀的道長。 經(jīng)常有香客問我语稠,道長宋彼,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任仙畦,我火速辦了婚禮输涕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘慨畸。我一直安慰自己莱坎,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布寸士。 她就那樣靜靜地躺著檐什,像睡著了一般。 火紅的嫁衣襯著肌膚如雪弱卡。 梳的紋絲不亂的頭發(fā)上乃正,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天,我揣著相機與錄音婶博,去河邊找鬼瓮具。 笑死,一個胖子當(dāng)著我的面吹牛凡人,可吹牛的內(nèi)容都是我干的名党。 我是一名探鬼主播,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼挠轴,長吁一口氣:“原來是場噩夢啊……” “哼传睹!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起岸晦,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤欧啤,失蹤者是張志新(化名)和其女友劉穎睛藻,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體堂油,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡修档,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年碧绞,在試婚紗的時候發(fā)現(xiàn)自己被綠了府框。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡讥邻,死狀恐怖迫靖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情兴使,我是刑警寧澤系宜,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站发魄,受9級特大地震影響盹牧,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜励幼,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一汰寓、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧苹粟,春花似錦有滑、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至苛秕,卻和暖如春肌访,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背艇劫。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工吼驶, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人港准。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓旨剥,卻偏偏與公主長得像,于是被迫代替她去往敵國和親浅缸。 傳聞我的和親對象是個殘疾皇子轨帜,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,724評論 2 354

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,110評論 25 707
  • 從三月份找實習(xí)到現(xiàn)在,面了一些公司衩椒,掛了不少蚌父,但最終還是拿到小米哮兰、百度、阿里苟弛、京東喝滞、新浪、CVTE膏秫、樂視家的研發(fā)崗...
    時芥藍(lán)閱讀 42,246評論 11 349
  • *面試心聲:其實這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個offer,總結(jié)起來就是把...
    Dove_iOS閱讀 27,139評論 30 470
  • 很早以前 大概是在15年的十月份就得知有一本新書即將出版 當(dāng)時特別讓我關(guān)注這本書是緣由書中的一句話:“厭倦的是日常...
    陽春白雪ycy閱讀 550評論 0 0
  • 1.把WMwareTools拷貝出來到桌面2.然后打開終端解壓右遭。命令: tar -xzvf VMwareTool...
    寂寞杰羅閱讀 752評論 0 0