Python 在子进程已经启动后授予对共享内存的访问权限

Python 在子进程已经启动后授予对共享内存的访问权限,python,ipc,multiprocessing,shared-memory,Python,Ipc,Multiprocessing,Shared Memory,如果数据只有在子进程生成后才可用(使用),我如何让子进程访问共享内存中的数据 我知道,但我不知道如何让我的子进程访问进程启动后创建的RawArray 数据由父进程生成,数据量事先未知 如果不是因为这个原因,我将使用线程,这将使这个任务变得更简单。使用非CPython实现不是一个选项 从引擎盖下看,似乎分配了共享的ctype对象 因此,这个问题实际上可以归结为:如果子进程生成后父进程调用了mmap(),那么子进程可以访问匿名映射的内存吗? 这在某种程度上与中的问题类似,只是在我的例子中,mmap

如果数据只有在子进程生成后才可用(使用),我如何让子进程访问共享内存中的数据

我知道,但我不知道如何让我的子进程访问进程启动后创建的
RawArray

数据由父进程生成,数据量事先未知

如果不是因为这个原因,我将使用线程,这将使这个任务变得更简单。使用非CPython实现不是一个选项


从引擎盖下看,似乎分配了共享的ctype对象

因此,这个问题实际上可以归结为:如果子进程生成后父进程调用了
mmap()
,那么子进程可以访问匿名映射的内存吗?

这在某种程度上与中的问题类似,只是在我的例子中,
mmap()
的调用方是父进程,而不是子进程


(已解决) 我创建了自己版本的
RawArray
,在引擎盖下使用
shm_open()
。只要标识符(
标记
)匹配,生成的共享ctypes数组就可以与任何进程共享


有关详细信息和示例,请参见。

我想您正在寻找

关于数据的序列化,当然如果你希望避免复制,我没有解决办法

编辑

事实上,您可以使用CPython 3.2中的非stdlib_mutliprocessing模块获取mmap对象的地址,并将其与ctypes对象的from_地址一起使用 这就是RawArray实际上所做的。当然,您不应该尝试调整mmap对象的大小,因为在这种情况下,mmap的地址可能会更改

import mmap
import _multiprocessing
from ctypes import Structure,c_int

map = mmap.mmap(-1,4)
class A(Structure):
    _fields_ = [("x", c_int)]
x = _multiprocessing.address_of_buffer(map)
b=A.from_address(x[0])
b.x = 256

>>> map[0:4]
'\x00\x01\x00\x00'
要在创建子对象后公开内存,必须将内存映射到正在调用的真实文件

map = mmap.mmap(open("hello.txt", "r+b").fileno(),4)

您的问题听起来非常适合于,它为共享内存、信号量和消息队列公开POSIX或SysV API。这里的特征矩阵包含了从他提供的模块中挑选的优秀建议

匿名
mmap(2)
区域的问题在于,您无法轻松地将它们与其他进程共享——如果它们是文件备份的,这将很容易,但是如果您实际上不需要该文件来做任何其他事情,这会让人觉得很傻。如果是C语言,您可以在
CLONE(2)
系统调用中使用
CLONE\u VM
标志,但我不想尝试将其与可能对内存安全做出假设的语言解释器一起使用。(即使在C语言中,这也有点危险,因为五年后的维护程序员也可能会被
CLONE\u-VM
行为所震惊。)

但是SysV和较新的POSIX共享内存映射甚至允许不相关的进程通过标识符从共享内存中附加和分离,因此您只需将创建映射的进程中的标识符与使用映射的进程共享,然后在操作映射中的数据时,它们可同时用于所有进程,而无需任何额外的解析开销。
shm_open(3)
函数返回一个
int
,该int在以后调用
ftruncate(2)
mmap(2)
时用作文件描述符,因此,其他进程可以使用共享内存段,而无需在文件系统中创建文件——即使所有使用共享内存段的进程都已退出,该内存也将保持不变。(对于Unix来说可能有点奇怪,但它很灵活。)

免责声明:我是问题的作者

我最终使用该模块创建了我自己的版本。我主要使用了
posix_ipc.SharedMemory
,它在引擎盖下调用

我的实现(
ShmemRawArray
)公开了与
RawArray
相同的功能,但需要两个额外的参数-一个
标记来唯一标识共享内存区域,另一个
创建
标志来确定是创建新的共享内存段还是附加到现有的共享内存段

如果有人感兴趣,这里有一份副本:

使用说明:

  • 前两个参数(
    typecode\u或\u type
    size\u或\u初始值设定项
    )的工作原理应与
    RawArray
    相同
  • 只要
    tag
    匹配,任何进程都可以访问共享阵列
  • 删除源对象(由
    ShmemRawArray(…,create=True)返回)
    时,共享内存段将取消链接
  • 使用当前存在的
    标记创建共享数组将引发
    存在错误
  • 使用不存在(或已取消链接)的
    标记访问共享阵列也会引发
    存在错误

一个(简短的、自包含的、可编译的示例)展示了它的实际应用

#!/usr/bin/env python2.7
import ctypes
import multiprocessing
from random import random, randint
from shmemctypes import ShmemRawArray

class Point(ctypes.Structure):
    _fields_ = [ ("x", ctypes.c_double), ("y", ctypes.c_double) ]

def worker(q):
    # get access to ctypes array shared by parent
    count, tag = q.get()
    shared_data = ShmemRawArray(Point, count, tag, False)

    proc_name = multiprocessing.current_process().name
    print proc_name, ["%.3f %.3f" % (d.x, d.y) for d in shared_data]

if __name__ == '__main__':
    procs = []
    np = multiprocessing.cpu_count()
    queue = multiprocessing.Queue()

    # spawn child processes
    for i in xrange(np):
        p = multiprocessing.Process(target=worker, args=(queue,))
        procs.append(p)
        p.start()

    # create a unique tag for shmem segment
    tag = "stack-overflow-%d" % multiprocessing.current_process().pid

    # random number of points with random data
    count = randint(3,10) 
    combined_data = [Point(x=random(), y=random()) for i in xrange(count)]

    # create ctypes array in shared memory using ShmemRawArray
    # - we won't be able to use multiprocssing.sharectypes.RawArray here 
    #   because children already spawned
    shared_data = ShmemRawArray(Point, combined_data, tag)

    # give children info needed to access ctypes array
    for p in procs:
        queue.put((count, tag))

    print "Parent", ["%.3f %.3f" % (d.x, d.y) for d in shared_data]
    for p in procs:
        p.join()
运行此操作将产生以下输出:

[me@home]$ ./shmem_test.py
Parent ['0.633 0.296', '0.559 0.008', '0.814 0.752', '0.842 0.110']
Process-1 ['0.633 0.296', '0.559 0.008', '0.814 0.752', '0.842 0.110']
Process-2 ['0.633 0.296', '0.559 0.008', '0.814 0.752', '0.842 0.110']
Process-3 ['0.633 0.296', '0.559 0.008', '0.814 0.752', '0.842 0.110']
Process-4 ['0.633 0.296', '0.559 0.008', '0.814 0.752', '0.842 0.110']

除非我弄错了,否则这将要求我序列化数据,然后将其加载到子进程中。这正是我试图避免的。据我所知,您试图避免广播消息,而不是真正避免序列化。我担心的是性能和内存使用。必须在所有进程上反序列化相同的数据听起来并不吸引人,因此我对序列化发表了评论。感谢Xavier的更新。恐怕我不明白实现我自己的mmap模块对我的情况会有什么帮助。这几乎就是在
多处理.sharedTypes.RawArray
的保护下所做的事情,所有这些都是宣传的。我正在尝试在子进程已经生成之后将共享内存公开给它们。您不能以消息容器(序列,
RawArray
,等等)作为参数启动进程吗?阿尔斯
[me@home]$ ./shmem_test.py
Parent ['0.633 0.296', '0.559 0.008', '0.814 0.752', '0.842 0.110']
Process-1 ['0.633 0.296', '0.559 0.008', '0.814 0.752', '0.842 0.110']
Process-2 ['0.633 0.296', '0.559 0.008', '0.814 0.752', '0.842 0.110']
Process-3 ['0.633 0.296', '0.559 0.008', '0.814 0.752', '0.842 0.110']
Process-4 ['0.633 0.296', '0.559 0.008', '0.814 0.752', '0.842 0.110']