将 multiprocessing.RawArray 传递给 C++ 函数
Passing multiprocessing.RawArray to a C++ function
我的 Python 应用程序使用 multiprocessing.RawArray
创建了一个在进程之间共享的数组。现在为了加快计算速度,我想从 C++ 函数中修改这个数组。将指向底层内存的指针传递给接受 void *
参数的 C++ 函数的安全方法是什么?
该函数在 pxd
文件中定义为:
cdef extern from 'lib/lib.hpp':
void fun(void *buffer)
到目前为止我天真的尝试:
buffer = multiprocessing.RawArray(ctypes.c_ubyte, 10000)
clib.fun(ctypes.cast(self.queue_obj_buffer, ctypes.c_void_p))
Cython 编译失败,出现以下错误:Cannot convert Python object to 'void *'
我也尝试了 ctypes.addressof
,结果相似。
我知道我需要一种方法来分别从每个参与进程查询此指针,因为同一内存区域在进程地址空间中的映射不同。但这不是问题,到目前为止,我只是在努力获得指针。我应该完全使用不同的方法并从 C++ 中分配共享内存,还是可以做我正在做的事情?
RawArray
应该有一个 buffer protocal, then it's easy to get the underlying pointer, since Cython has a good support for it via memory view,下面的代码应该可以工作:
%%cython
import ctypes
from multiprocessing.sharedctypes import RawArray
ctypedef unsigned char ubyte
cdef void func(void* buffer, int size):
cdef ubyte *buf = <ubyte*>buffer
cdef int i
for i in range(size):
buf[i] += 1
def test():
cdef ubyte[::1] view = RawArray(ctypes.c_ubyte, [1,2,3,4,5])
func(<void*>&view[0], len(view))
print(list(view))
test() # [2, 3, 4, 5, 6]
根据你的描述,你应该看看Cython对shared memory parallelism
的支持
multiprocessing.RawArray
是一个 ctypes.Array
, so the address of the underlying buffer can be obtained via ctypes.addressof
。该地址可以重新解释为 void *
。这是一个例子:
%%cython
# a small function for testing purposes:
cdef extern from *:
"""
unsigned char get_first(void *ptr){
unsigned char *ptr_as_ubytes = (unsigned char *)ptr;
return ptr_as_ubytes[0];
}
"""
unsigned char get_first(void *ptr)
import ctypes
def first_element(buffer):
cdef size_t ptr_address = ctypes.addressof(buffer) # size_t is big enough to hold the address
return get_first(<void*> ptr_address)
使用 <void*>ctypes.addressof(buffer)
将不起作用,因为 Cython 无法将 PyObject
自动转换为 void *
-(可读性较差的)oneliner 将是 <void*><size_t> ctypes.addressof(buffer)
:
- Cython 可以将 Python 对象转换为原始
size_t
(或任何整数)C 值。
- a
size_t
C 值在 C 语言中可以重新解释为 void *
。
下面是对上述示例功能的小测试:
import multiprocessing
import ctypes
buffer = multiprocessing.RawArray(ctypes.c_ubyte, 10000)
buffer[0]=42
first_element(buffer)
# 42
如果 C 函数的签名不期望 void *
而是例如 unsigned char
类型的连续内存,那么@oz1 的方法更安全,因为它不仅保护数据不会被错误地重新解释,但也会自动检查缓冲区是否连续并且具有正确的维数(通过键入 unsigned char[::1]
来完成)。
我的 Python 应用程序使用 multiprocessing.RawArray
创建了一个在进程之间共享的数组。现在为了加快计算速度,我想从 C++ 函数中修改这个数组。将指向底层内存的指针传递给接受 void *
参数的 C++ 函数的安全方法是什么?
该函数在 pxd
文件中定义为:
cdef extern from 'lib/lib.hpp':
void fun(void *buffer)
到目前为止我天真的尝试:
buffer = multiprocessing.RawArray(ctypes.c_ubyte, 10000)
clib.fun(ctypes.cast(self.queue_obj_buffer, ctypes.c_void_p))
Cython 编译失败,出现以下错误:Cannot convert Python object to 'void *'
我也尝试了 ctypes.addressof
,结果相似。
我知道我需要一种方法来分别从每个参与进程查询此指针,因为同一内存区域在进程地址空间中的映射不同。但这不是问题,到目前为止,我只是在努力获得指针。我应该完全使用不同的方法并从 C++ 中分配共享内存,还是可以做我正在做的事情?
RawArray
应该有一个 buffer protocal, then it's easy to get the underlying pointer, since Cython has a good support for it via memory view,下面的代码应该可以工作:
%%cython
import ctypes
from multiprocessing.sharedctypes import RawArray
ctypedef unsigned char ubyte
cdef void func(void* buffer, int size):
cdef ubyte *buf = <ubyte*>buffer
cdef int i
for i in range(size):
buf[i] += 1
def test():
cdef ubyte[::1] view = RawArray(ctypes.c_ubyte, [1,2,3,4,5])
func(<void*>&view[0], len(view))
print(list(view))
test() # [2, 3, 4, 5, 6]
根据你的描述,你应该看看Cython对shared memory parallelism
的支持multiprocessing.RawArray
是一个 ctypes.Array
, so the address of the underlying buffer can be obtained via ctypes.addressof
。该地址可以重新解释为 void *
。这是一个例子:
%%cython
# a small function for testing purposes:
cdef extern from *:
"""
unsigned char get_first(void *ptr){
unsigned char *ptr_as_ubytes = (unsigned char *)ptr;
return ptr_as_ubytes[0];
}
"""
unsigned char get_first(void *ptr)
import ctypes
def first_element(buffer):
cdef size_t ptr_address = ctypes.addressof(buffer) # size_t is big enough to hold the address
return get_first(<void*> ptr_address)
使用 <void*>ctypes.addressof(buffer)
将不起作用,因为 Cython 无法将 PyObject
自动转换为 void *
-(可读性较差的)oneliner 将是 <void*><size_t> ctypes.addressof(buffer)
:
- Cython 可以将 Python 对象转换为原始
size_t
(或任何整数)C 值。 - a
size_t
C 值在 C 语言中可以重新解释为void *
。
下面是对上述示例功能的小测试:
import multiprocessing
import ctypes
buffer = multiprocessing.RawArray(ctypes.c_ubyte, 10000)
buffer[0]=42
first_element(buffer)
# 42
如果 C 函数的签名不期望 void *
而是例如 unsigned char
类型的连续内存,那么@oz1 的方法更安全,因为它不仅保护数据不会被错误地重新解释,但也会自动检查缓冲区是否连续并且具有正确的维数(通过键入 unsigned char[::1]
来完成)。