gpt4 book ai didi

python - Cython prange 与字符串数组

转载 作者:太空宇宙 更新时间:2023-11-03 21:09:06 25 4
gpt4 key购买 nike

我正在尝试使用 prange 来处理多个字符串。由于无法使用 python 列表执行此操作,因此我使用 numpy 数组。

对于 float 数组,此函数可以工作:

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 和字符串数组?

最佳答案

除此之外,您的代码在 cythonized 时应该会失败,因为您尝试创建一个没有 gil 的 Python 对象(即 str(i) ),您的代码没有执行您认为应该执行的操作。

为了分析发生了什么,让我们看一个非常简单的 cython-version:

%%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 构建的,因此我使用 -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

所以x不是 unicode 对象的集合。 x 的一个元素由 5 个 unicode 字符组成,这些元素一个接一个地连续存储在内存中。重要的是:与存储在不同内存布局中的 unicode 对象中的信息相同。

这是 numpy 的怪癖之一以及如何 np.array工作原理:列表中的每个元素都转换为 unicode 对象,然后计算元素的最大大小并计算并使用 dtype(在本例中为 <U5 )。

<强> np.str在 cython 代码 ( ar[np.str] x ) 中的解释不同(两次!)

第一个区别:在你的 Python3 代码中 np.str用于unicode ,但是在你的 cython 代码中,它被 cythonized 为 language_level=2 , np.str用于bytes (参见doc)。

第二个区别:看到np.str ,Cython 会将其解释为带有 Python 对象的数组(也许它应该被视为 Cython-bug) - 它几乎与 dtype 相同。是np.object - 实际上与 np.object 的唯一区别错误消息略有不同。

有了这些信息我们就可以理解错误消息了。在运行时,输入数组被检查(在函数的第一行执行之前!):

  1. 预期是一个包含 python 对象的数组,即 8 字节指针,即元素大小为 8 字节的数组
  2. 收到的是一个数组,元素大小为5*4=20字节(一个unicode字符为4字节)

因此无法完成转换并引发观察到的异常。

您无法更改 <U.. 中元素的大小-numpy-array:

现在让我们看一下以下内容:

>>> x = np.array(["apple", b"pear"], dtype=np.str)
>>> x[0] = x[0]+str(0)
>>> x[0]
'apple'

元素没有改变,因为字符串 x[0]+str(0)写回 x 时被截断-array:只能容纳5个字符!它可以与 "pear" 一起工作(在某种程度上,只要生成的字符串不超过 5 个字符)不过:

>>> x[1] = x[1]+str(1)
>>> x[1]
'pear0'
<小时/>

这一切让你怎么办?

  • 您可能想使用bytes而不是unicodes (即dtype=np.bytes_)
  • 鉴于您不知道编译类型下 numpy 数组的元素大小,您应该声明输入数组 xar x在签名中并推出运行时检查,类似于 Cython 的 "depricated" numpy-tutorial 中所做的操作.
  • 如果应就地进行更改,则输入数组中的元素对于生成的字符串应该足够大。

以上所有,与prange无关。使用prange您不能使用str(i)因为它在 python 对象上运行。

关于python - Cython prange 与字符串数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55190780/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com