在多个平台上跨 python 个进程同步由 ctypes 指针表示的内存
Syncronizing memory represented by ctypes pointers accross python processes on multiple platforms
我是 运行 两名 Python 3 名口译员,一名在 Linux 上,一名在 Windows 系统上。他们使用 multiprocessing.connection
(Client
和 Listener
)进行通信(即交换数据)。在两者之间,我必须保持由 ctypes
指针表示的任意数据结构的内容同步。
问题是我需要高效地来回传送数据内容。 multiprocessing.connection
将 pickle
传送任何数据,因此我必须将数据序列化为可以 pickle 的内容。
到目前为止,我将内存中的每个字节序列都变成了一个 Python 列表 Python 整数。嗯,它(至少)有效......
def generate_pointer_from_int_list(int_array):
return ctypes.pointer((ctypes.c_ubyte * len(int_array))(*int_array))
def overwrite_pointer_with_int_list(ctypes_pointer, int_array):
(ctypes.c_ubyte * len(int_array)).from_address(ctypes.c_void_p.from_buffer(ctypes_pointer).value)[:] = int_array[:]
def serialize_pointer_into_int_list(ctypes_pointer, size_bytes):
return (ctypes.c_ubyte * size_bytes).from_address(ctypes.c_void_p.from_buffer(ctypes_pointer).value)[:]
我想知道是否有办法提高效率(就需要传输的数据量和速度而言,当然)。
我的一个想法是使用 Python 字节的字符串而不是整数列表,这将减少所需的内存量。但是,我没能成功。我该如何更改上述例程?
我还有哪些可能更好/更快/内存效率更高的选项?
serialize_pointer_into_int_list
的用法示例:
sample_len = 5
sample_p = ctypes.pointer((ctypes.c_double * sample_len)(1.0, 2.0, 3.0, 4.0, 5.0))
sample_int_list = serialize_pointer_into_int_list(sample_p, sample_len * ctypes.sizeof(ctypes.c_double))
print(sample_int_list)
print(type(sample_int_list))
输出:
[0, 0, 0, 0, 0, 0, 240, 63, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 8, 64, 0, 0, 0, 0, 0, 0, 16, 64, 0, 0, 0, 0, 0, 0, 20, 64]
<class 'list'>
假设每个数据部分都没有那么大(因为解决方案需要复制),可以通过这种方式完成(在交互式 shell 中显示):
>>> import pickle
>>> import ctypes
>>> b = (ctypes.c_double * 5)(1.0, 2.0, 3.0, 4.0, 5.0) # Arbitrary data
>>> d = pickle.dumps(bytes(b))
>>> c = pickle.loads(d)
>>> a = (ctypes.c_double * 5).from_buffer_copy(c)
>>> a
<__main__.c_double_Array_5 object at 0x02F6C9E0>
>>> list(a)
[1.0, 2.0, 3.0, 4.0, 5.0]
我是 运行 两名 Python 3 名口译员,一名在 Linux 上,一名在 Windows 系统上。他们使用 multiprocessing.connection
(Client
和 Listener
)进行通信(即交换数据)。在两者之间,我必须保持由 ctypes
指针表示的任意数据结构的内容同步。
问题是我需要高效地来回传送数据内容。 multiprocessing.connection
将 pickle
传送任何数据,因此我必须将数据序列化为可以 pickle 的内容。
到目前为止,我将内存中的每个字节序列都变成了一个 Python 列表 Python 整数。嗯,它(至少)有效......
def generate_pointer_from_int_list(int_array):
return ctypes.pointer((ctypes.c_ubyte * len(int_array))(*int_array))
def overwrite_pointer_with_int_list(ctypes_pointer, int_array):
(ctypes.c_ubyte * len(int_array)).from_address(ctypes.c_void_p.from_buffer(ctypes_pointer).value)[:] = int_array[:]
def serialize_pointer_into_int_list(ctypes_pointer, size_bytes):
return (ctypes.c_ubyte * size_bytes).from_address(ctypes.c_void_p.from_buffer(ctypes_pointer).value)[:]
我想知道是否有办法提高效率(就需要传输的数据量和速度而言,当然)。
我的一个想法是使用 Python 字节的字符串而不是整数列表,这将减少所需的内存量。但是,我没能成功。我该如何更改上述例程?
我还有哪些可能更好/更快/内存效率更高的选项?
serialize_pointer_into_int_list
的用法示例:
sample_len = 5
sample_p = ctypes.pointer((ctypes.c_double * sample_len)(1.0, 2.0, 3.0, 4.0, 5.0))
sample_int_list = serialize_pointer_into_int_list(sample_p, sample_len * ctypes.sizeof(ctypes.c_double))
print(sample_int_list)
print(type(sample_int_list))
输出:
[0, 0, 0, 0, 0, 0, 240, 63, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 8, 64, 0, 0, 0, 0, 0, 0, 16, 64, 0, 0, 0, 0, 0, 0, 20, 64]
<class 'list'>
假设每个数据部分都没有那么大(因为解决方案需要复制),可以通过这种方式完成(在交互式 shell 中显示):
>>> import pickle
>>> import ctypes
>>> b = (ctypes.c_double * 5)(1.0, 2.0, 3.0, 4.0, 5.0) # Arbitrary data
>>> d = pickle.dumps(bytes(b))
>>> c = pickle.loads(d)
>>> a = (ctypes.c_double * 5).from_buffer_copy(c)
>>> a
<__main__.c_double_Array_5 object at 0x02F6C9E0>
>>> list(a)
[1.0, 2.0, 3.0, 4.0, 5.0]