我正在尝试使用multiprocessing in Python,但是,我在创建一些shared memory时遇到了麻烦。以下示例说明我的问题:
在引用the following时(稍微不同,因为他使用了一个充满浮点数的矩阵,但原理相同),我想将一个numpy字符串矩阵转换为shared memory空间以供进程使用。我有以下内容:
from ctypes import c_wchar_p
import numpy as np
from multiprocessing.sharedctypes import Array
input_array = np.array([['Red', 'Green', 'Blue', 'Yellow'],
['Purple', 'Orange', 'Cyan', 'Pink']]).T
shared_memory = Array(c_wchar_p, input_array.size, lock=False) # Equivalent to just using a RawArray
np_wrapper = np.frombuffer(shared_memory, dtype='<U1').reshape(input_array.shape)
np.copyto(np_wrapper, input_array)
print(np_wrapper)
但是,np_wrapper
只有每个字符串的第一个字符:
[['R' 'P']
['G' 'O']
['B' 'C']
['Y' 'P']]
我试图纠正这个问题:
dtype
函数的<U1
从<U6
更改为dtype
,这是input_array
的{{1}}。但是,它会抛出以下异常:ValueError:缓冲区大小必须是元素大小的倍数
dtype
frombuffer
和int64
函数,因为我的shared_memory
数组类型为frombuffer
(即字符串指针)而我是在64位Windows 10系统上。但是,它会抛出以下异常:ValueError:无法将大小为4的数组转换为形状(4,2)
我非常困惑为什么我的打字错了。 是否有人对如何解决此问题有任何见解?
答案 0 :(得分:1)
了解这个字符串数组包含的内容可能会有所帮助:
In [643]: input_array = np.array([['Red', 'Green', 'Blue', 'Yellow'],
...: ['Purple', 'Orange', 'Cyan', 'Pink']]).T
...:
...:
In [644]: input_array.size
Out[644]: 8
In [645]: input_array.itemsize
Out[645]: 24
In [646]: input_array.nbytes
Out[646]: 192
因为它是转置,所以形状和步幅与输入数组不同,但字符串按原始顺序排列。
In [647]: input_array.__array_interface__
Out[647]:
{'data': (139792902236880, False),
'strides': (24, 96),
'descr': [('', '<U6')],
'typestr': '<U6',
'shape': (4, 2),
'version': 3}
我的猜测是Array
应该使用nbytes
而不是size
进行定义。
答案 1 :(得分:1)
在我详细说明我的解决方案之前,我想在一些有用的信息前面给我答案。事实证明,python中的函数memoryview()
对于全面了解非常有用。例如,在将input_array
的dtype指定为dtype='S6'
(b / c减去要检查的字节数)后运行以下命令:
print(bytes(memoryview(input_array)))
然后得到以下结果:
b'Red\x00\x00\x00PurpleGreen\x00OrangeBlue\x00\x00Cyan\x00\x00YellowPink\x00\x00'
我们可以通过以下输出看到input_array
中的每个条目都有6个字节的长度,并且在一个连续的内存块中布局。这告诉我们我们的Numpy数组不只是指向内存中字符串的8个指针。
回到指定dtype
不的时候,@ hpaulj还提供了更有帮助的见解。阅读dtype documentation后,我们的数组的类型为<U6
,其转换如下:
< -- Little-Endian (b/c I am on an Intel-based system)
U -- Unicode String (Remember with 4 bytes per Unicode String)
6 -- 24 bytes per entry in the array.
from ctypes import c_char
import numpy as np
from multiprocessing.sharedctypes import Array
input_array = np.array([['Red', 'Green', 'Blue', 'Yellow'],
['Purple', 'Orange', 'Cyan', 'Pink']]).T
shared_memory = Array(c_char, input_array.size * input_array.itemsize, lock=False)
np_wrapper = np.frombuffer(shared_memory, dtype=input_array.dtype).reshape(input_array.shape)
np.copyto(np_wrapper, input_array)
print(shared_memory[:])
print(np_wrapper)
初始代码的第一个不正确的方面是初始shared_memory
数组的输入信息。我们的Numpy数组不是一个指针数组,而是8个字符串紧密相邻地压缩(一些填充由最长的元素决定)。因此,使用类型c_wchar_p
(即字符串指针)不正确。我选择c_char
而不是c_wchar
因为c_char
保证是一个字节,而c_wchar
不是see documentation for further details。
接下来,需要指定共享内存的整个大小。因为我选择了c_char
作为我的类型,所以我将指定字节数。长度由以下给出:
有8个元素(
input_array.size
),每个元素包含24个字节(input_array.itemsize
)。因此,共享内存总共有8 * 24 = 192个字节。
最后,在Numpy中使用frombuffer
函数时,请务必指定正确 dtype
,因为这是Numpy将如何分割并解释任意字节的来源只需使用dtype
input_array
完成翻译即可。
最后,copyto
开始后,shared_memory
将成功配置!