Python 涉及 C 对象的多处理共享内存问题

Python multiprocessing shared memory issues with C objects involved

我正在开发一个程序,该程序使用外部 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 对象(以及其他对象) Python 进程之间由顶级 CObject 指向的。

以防万一,好消息是我可以只读访问...

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

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

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

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

您可以将对象序列化为某种二进制表示形式,并通过 pipe(2) (also available via os.pipe() in Python). For simple cases, this is a field-by-field copy, but again, pointers will need care. You will have to (un)swizzle your pointers 传递它以使它们在(反)序列化后正常工作。这是最容易推广的技术,但需要了解对象的结构,或为您执行序列化的黑盒函数。

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

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