2015-08-24 102 views
1

我正在使用外部C庫解析來自外部源的數據和Python庫來運行一些優化問題的程序。優化是非常耗時的,因此使用多個CPU將是一個重要的優勢。涉及C對象的Python多處理共享內存問題

基本上,我裹C(++)與用Cython結構如下:

cdef class CObject(object): 

    cdef long p_sthg 
    cdef OBJECT* sthg 

    def __cinit__(self, sthg): 
     self.p_sthg = sthg 
     self.sthg = <OBJECT*> self.p_sthg 

    def __reduce__(self): 
     return (rebuildObject, (self.p_sthg,)) 

    def getManyThings(self): 
     ... 
     return blahblahblah 

然後創建我的資源密集的過程:

p = mp.Process(target=make_process, args=((cobject,))) 

正如你可以立即猜出(當然我沒有),即使我設法取消了CObject,指針卻被傳遞給新的進程,但不是它引用的C結構。

我可以找到一些資源解釋如何將Python對象放入共享內存中,但這在我的情況下還不夠,因爲我需要共享我幾乎不知道的C對象(以及其他指向的對象頂級CObject)在Python進程之間。

如果它的事項,好事是,我可以只讀訪問我們存活......

沒有人有與該事項有關的經驗嗎?
我的另一個想法是找到一種方法來編寫我需要傳遞到文件中的對象的二進制表示形式,並從另一個進程中讀取它...

回答

2

沒有單一的一般方法來執行此操作。

通過在合適的mmap(2)區域內構建它(也可以通過Python標準庫中的mmap;使用MAP_SHARED|MAP_ANONYMOUS),將C對象放入共享內存中。這要求整個對象位於mmap內,並且可能使對象無法使用指針(但是,如果它們指向mmap,則相對於對象的偏移可能是正確的)。如果對象具有任何文件描述符或其他任何類型的句柄,那麼這些句柄幾乎肯定無法正常工作。請注意0​​就像malloc();您必須執行相應的munmap()或泄漏內存。

您可以將拷貝到將C對象分成共享內存(例如memcpy(3))。這可能效率較低,並且要求該對象合理可複製。 memcpy不會奇蹟般地修復指針和其他引用。另一方面,這並不要求你控制對象的構造。

您可以將對象序列化爲某些二進制表示形式,並將其傳遞給pipe(2)(也可通過Python中的os.pipe()獲取)。對於簡單的情況,這是一個逐場複製,但同樣需要注意指針。 (德)序列化後,您將不得不(un)swizzle your pointers使它們正常工作。這是最容易泛化的技術,但需要知道對象是如何構造的,或者需要知道該對象是如何構造的,或者需要一個黑盒函數來爲您執行序列化。

最後,您可以在/dev/shm中創建臨時文件並以此方式交換信息。這些文件由RAM支持,實際上與共享內存相同,但可能具有更熟悉的類似文件的界面。但是這僅限於Unix。在Linux以外的系統上,您應該使用shm_open(3)以實現完全的可移植性。

請注意,共享內存通常會存在問題。它需要進程間同步,但必要的鎖定原語遠不如線程世界那樣發達。我建議將共享內存限制爲不可變對象或固有鎖定設計(這很難得到正確的設計)。

+0

我的結構並不複雜,但鏈接到其他結構的std :: list,它們本身鏈接到其他結構的std :: list(我沒有檢查遞歸級別,但沒有循環.. 。)我猜Cython並沒有被設計爲欺騙分配器(用'boost'找到的東西,但沒有更基本的東西?),並手動調整剩餘的指針......我可能有一個特定於我的需求的解決方法(通過調用數據獲取從過程和修剪什麼我需要,更安全!)但是wul仍然喜歡看到一個隱藏的std :: list 測試案例通過Cython中的共享內存... – xoolive

+0

@xoolive:一個列表是由許多指針,最封裝。如果您嘗試分享它,那些指針將不起作用,整個事情就會炸燬。顯然[Boost可以做到這一點](http://www.boost.org/doc/libs/1_59_0/doc/html/interprocess.html),但這是一個額外的依賴項,看起來並不直接在STL上工作容器。遞歸地遍歷列表並逐個序列化其元素可能會更簡單。 – Kevin