【问题标题】:Python multiprocessing shared memory issues with C objects involved涉及 C 对象的 Python 多处理共享内存问题
【发布时间】:2015-11-18 01:55:58
【问题描述】:

我正在开发一个程序,该程序使用外部 C 库来解析来自外部源的数据,并使用 Python 库来运行一些优化问题。优化非常耗时,因此使用多个 CPU 将是一个重要的优势。

基本上,我用 Cython 包装了 C(++) 结构,如下所示:

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 进程。

万一这很重要,好处是我可以通过只读访问来生存......

有人有这方面的经验吗?
我的另一个想法是找到一种方法来编写我需要传递到文件中的对象的二进制表示并从其他进程中读取它......

【问题讨论】:

    标签: python cython shared-memory python-multiprocessing


    【解决方案1】:

    没有单一的通用方法可以做到这一点。

    您可以通过在合适的mmap(2) 区域中构造 C 对象来将其放入共享内存中(也可以通过 Python 标准库中的mmap 获得;使用MAP_SHARED|MAP_ANONYMOUS)。这要求整个对象位于 mmap 内,并且可能会使对象无法使用指针(但相对于对象的偏移量可能是可以的,前提是它们指向 mmap 内)。如果对象有任何文件描述符或任何类型的其他句柄,那么这些几乎肯定不会正常工作。注意mmap() 类似于malloc();你必须做一个相应的munmap() 否则你会泄漏内存。

    您可以将 C 对象复制到共享内存中(例如memcpy(3))。这可能效率较低,并且要求对象可合理复制。 memcpy 不会神奇地修复指针和其他引用。从好的方面来说,这不需要您控制对象的构造。

    您可以将对象序列化为某种二进制表示并通过pipe(2) 传递它(也可以通过Python 中的os.pipe() 获得)。对于简单的情况,这是逐个字段的副本,但同样需要注意指针。您必须(un)swizzle your pointers 才能使它们在(反)序列化后正常工作。这是最容易推广的技术,但需要了解对象的结构,或为您执行序列化的黑盒函数。

    最后,您可以在/dev/shm 中创建临时文件并以这种方式交换信息。这些文件由 RAM 支持,实际上与共享内存相同,但可能具有更熟悉的类似文件的界面。但这仅适用于 Unix。在 Linux 以外的系统上,您应该使用 shm_open(3) 以获得完全的可移植性。

    请注意,共享内存通常会出现问题。它需要进程间同步,但必要的锁定原语远没有线程世界那么发达。我建议将共享内存限制为不可变对象或固有的无锁设计(这很难做到正确)。

    【讨论】:

    • 我的结构并没有那么复杂,而是链接到其他结构的 std::list,它们本身链接到其他结构的 std::list (我没有检查递归级别,但是有没有循环......)我猜 Cython 的设计并不是为了欺骗分配器(用boost 找到东西,但没有更基本的东西?)并手动调整剩余的指针......我可能有一个特定于我需要的解决方法(通过调用从进程中获取的数据并修剪我需要的数据,更安全!)但我仍然希望看到隐藏的 std::list 的测试用例通过 Cython 中的共享内存...
    • @xoolive:一个列表由许多指针组成,大部分是封装的。如果您尝试分享这些指针将不起作用,整个事情都会爆炸。显然Boost can do this,但这是一个额外的依赖项,看起来它不能直接在 STL 容器上工作。递归遍历您的列表并一次序列化其元素可能会更简单。
    猜你喜欢
    • 1970-01-01
    • 2012-05-30
    • 1970-01-01
    • 1970-01-01
    • 2015-03-15
    • 2013-08-19
    • 1970-01-01
    • 2017-02-07
    相关资源
    最近更新 更多