簡體   English   中英

與 Python 多處理共享對象數組

[英]Sharing array of objects with Python multiprocessing

For this question, I refer to the example in Python docs discussing the "use of the SharedMemory class with NumPy arrays, accessing the same numpy.ndarray from two distinct Python shells".

我想實現的一個主要更改是操作 class 對象數組,而不是 integer 值,如下所示。

import numpy as np
from multiprocessing import shared_memory    

# a simplistic class example
class A(): 
    def __init__(self, x): 
        self.x = x

# numpy array of class objects 
a = np.array([A(1), A(2), A(3)])       

# create a shared memory instance
shm = shared_memory.SharedMemory(create=True, size=a.nbytes, name='psm_test0')

# numpy array backed by shared memory
b = np.ndarray(a.shape, dtype=a.dtype, buffer=shm.buf)                                    

# copy the original data into shared memory
b[:] = a[:]                                  

print(b)                                            

# array([<__main__.Foo object at 0x7fac56cd1190>,
#       <__main__.Foo object at 0x7fac56cd1970>,
#       <__main__.Foo object at 0x7fac56cd19a0>], dtype=object)

現在,在不同的 shell 中,我們附加到共享的 memory 空間並嘗試操作數組的內容。

import numpy as np
from multiprocessing import shared_memory

# attach to the existing shared space
existing_shm = shared_memory.SharedMemory(name='psm_test0')

c = np.ndarray((3,), dtype=object, buffer=existing_shm.buf)

甚至在我們能夠操作c ,打印它就會導致分段錯誤。 事實上,我不能指望觀察到尚未寫入模塊的行為,所以我的問題是如何處理共享對象數組?

我目前正在挑選列表,但受保護的讀/寫會增加相當多的開銷。 我也嘗試過使用Namespace ,這很慢,因為不允許索引寫入。 另一個想法可能是在 ShareableList 中使用ShareableList Ctypes 結構,但我不知道從哪里開始。

此外還有一個設計方面: shared_memory中似乎有一個開放的錯誤可能會影響我的實現,其中我有幾個進程在處理數組的不同元素。

是否有一種更可擴展的方式在多個進程之間共享大量對象列表,以便在任何給定時間所有正在運行的進程都與列表中的唯一對象/元素交互?

更新:在這一點上,我也將接受部分答案,討論是否可以通過 Python 來實現。

所以,我做了一些研究( Shared Memory Objects in Multiprocessing )並提出了一些想法:

通過 numpy 字節數組

序列化對象,然后將它們作為字節字符串保存到 numpy 數組中。 這里有問題的是

  1. 需要將數據類型從 'psm_test0' 的創建者傳遞給 ' 'psm_test0' 'psm_test0'的任何消費者。 這可以通過另一個共享的 memory 來完成。

  2. pickleunpickle本質上類似於deepcopy ,即它實際上復制了底層數據。

“主”進程的代碼如下:

import pickle
from multiprocessing import shared_memory
import numpy as np


# a simplistic class example
class A():
    def __init__(self, x):
        self.x = x

    def pickle(self):
        return pickle.dumps(self)

    @classmethod
    def unpickle(self, bts):
        return pickle.loads(bts)


if __name__ == '__main__':
    # Test pickling procedure
    a = A(1)
    print(A.unpickle(a.pickle()).x)
    # >>> 1

    # numpy array of byte strings
    a_arr = np.array([A(1).pickle(), A(2).pickle(), A('This is a really long test string which should exceed 42 bytes').pickle()])

    # create a shared memory instance
    shm = shared_memory.SharedMemory(
        create=True,
        size=a_arr.nbytes,
        name='psm_test0'
    )

    # numpy array backed by shared memory
    b_arr = np.ndarray(a_arr.shape, dtype=a_arr.dtype, buffer=shm.buf)

    # copy the original data into shared memory
    b_arr[:] = a_arr[:]

    print(b_arr.dtype)
    # 'S105'

並且對於消費者

import numpy as np
from multiprocessing import shared_memory
from test import A

# attach to the existing shared space
existing_shm = shared_memory.SharedMemory(name='psm_test0')

c = np.ndarray((3,), dtype='S105', buffer=existing_shm.buf)

# Test data transfer
arr = [a.x for a in list(map(A.unpickle, c))]
print(arr)
# [1, 2, ...]

我想說你有幾種前進的方法:

  1. 保持簡單的數據類型。

  2. 使用 C api 實現一些東西,但我真的不能幫你。

  3. 使用Rust

  4. 使用馬槽 您可能會失去一些性能(盡管我希望看到一個真正的基准測試),但是您可以獲得一個相對安全且簡單的共享對象接口。

  5. 使用Redis ,它也有 Python 綁定...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM