我正在尝试使用prange来处理多个字符串。 由于无法使用python列表执行此操作,因此我使用的是numpy数组。
使用浮点数组时,此函数有效:
from cython.parallel import prange
cimport numpy as np
from numpy cimport ndarray as ar
cpdef func_float(ar[np.float64_t,cast=True] x, double alpha):
cdef int i
for i in prange(x.shape[0], nogil=True):
x[i] = alpha * x[i]
return x
当我尝试这个简单的方法时:
cpdef func_string(ar[np.str,cast=True] x):
cdef int i
for i in prange(x.shape[0], nogil=True):
x[i] = x[i] + str(i)
return x
我得到这个
>> func_string(x = np.array(["apple","pear"],dtype=np.str))
File "processing.pyx", line 8, in processing.func_string
cpdef func_string(ar[np.str,cast=True] x):
ValueError: Item size of buffer (20 bytes) does not match size of 'str object' (8 bytes)
我可能缺少一些东西,找不到str的替代品。 有没有办法正确地将prange与字符串数组一起使用?
答案 0 :(得分:0)
除了事实,因为您尝试创建不带gil的Python对象(即str(i)
)时,您的代码在被cython化后也会失败。
为了分析正在发生的事情,让我们看一个非常简单的cython版本:
%%cython -2
cimport numpy as np
from numpy cimport ndarray as ar
cpdef func_string(ar[np.str, cast=True] x):
print(len(x))
从您的错误消息中,您可以推断出您使用的是Python 3,并且Cython扩展是使用language_level=2
构建的(仍然默认),因此我在{{1}中使用了-2
}魔术细胞。
现在:
%%cython
这是怎么回事?
>>> x = np.array(["apple", "pear"], dtype=np.str)
>>> func_string(x)
ValueError: Item size of buffer (20 bytes) does not match size of 'str object' (8 bytes)
不是您认为的
首先,让我们看一下x
:
x
所以>>> x.dtype
<U5
不是Unicode对象的集合。 x
的一个元素由5个unicode字符组成,并且这些元素连续存储在内存中。重要的是:与存储在不同内存布局中的Unicode对象中的信息相同。
这是numpy的怪癖之一,以及x
的工作方式:列表中的每个元素都将转换为unicode对象,然后计算该元素的最大大小并加上dtype(在这种情况下,{{1} })进行计算和使用。
np.array
在cython代码(<U5
)中的解释不同(两次!)
第一个区别:您的Python3代码np.str
用于ar[np.str] x
,但是在您的cython代码(被np.str
进行了cythonized的情况下,unicode
则用于{{1 }}(请参阅doc)。
第二个区别:看到language_level=2
,Cython会将其解释为带有Python对象的数组(也许应该视为Cython-bug)-几乎与np.str
是{ {1}}-实际上与bytes
的唯一区别是错误消息略有不同。
使用此信息,我们可以了解错误消息。在运行时,将检查输入数组(在执行函数的第一行之前!):
因此无法进行强制转换,并且抛出观察到的异常。
您无法更改np.str
-numpy-array 中元素的大小:
现在让我们看一下以下内容:
dtype
该元素没有改变,因为字符串np.object
在写回到np.object
数组时被截断了:只有5个字符的位置!尽管可以使用<U..
(在某种程度上,只要结果字符串不超过5个字符)就可以了:
>>> x = np.array(["apple", b"pear"], dtype=np.str)
>>> x[0] = x[0]+str(0)
>>> x[0]
'apple'
这一切都会离开你吗?
x[0]+str(0)
而不是x
(即"pear"
)>>> x[1] = x[1]+str(1)
>>> x[1]
'pear0'
声明为bytes
并推出运行时检查,与Cython的"depricated" numpy-tutorial中的操作类似。以上所有与unicodes
无关。要使用dtype=np.bytes_
,您不能使用x
,因为它可以在python对象上运行。