在Cython中优化字符串

12 投票
1 回答
4533 浏览
提问于 2025-04-18 02:41

我正在向我们小组展示Cython的优点,主要是为了提高Python的性能。我已经展示了几个基准测试,所有这些测试都通过以下方式实现了加速:

  1. 编译现有的Python代码。
  2. 使用cdef来给变量静态类型,特别是在内部循环中。

不过,我们的很多代码都涉及字符串处理,而我还没能找到通过给Python字符串添加类型来优化代码的好例子。

我尝试过的一个例子是:

cdef str a
cdef int i,j
for j in range(1000000):
   a = str([chr(i) for i in range(127)])

但是把'a'定义为字符串实际上让代码运行得更慢。我看过关于“Unicode和传递字符串”的文档,但对它在我展示的例子中的应用感到困惑。我们不使用Unicode——所有内容都是纯ASCII。我们使用的是Python 2.7.2。

任何建议都非常感谢。

1 个回答

15

我建议你使用 cpython.array.array 来进行操作。最好的参考资料是 C API 和 Cython 的源代码(可以查看 这里)。

from cpython cimport array

def cfuncA():
    cdef str a
    cdef int i,j
    for j in range(1000):
        a = ''.join([chr(i) for i in range(127)])

def cfuncB():
    cdef:
        str a
        array.array[char] arr, template = array.array('c')
        int i, j

    for j in range(1000):
        arr = array.clone(template, 127, False)

        for i in range(127):
            arr[i] = i

        a = arr.tostring()

需要注意的是,所需的操作会根据你对字符串的处理方式而有很大不同。

>>> python2 -m timeit -s "import pyximport; pyximport.install(); import cyytn" "cyytn.cfuncA()"
100 loops, best of 3: 14.3 msec per loop

>>> python2 -m timeit -s "import pyximport; pyximport.install(); import cyytn" "cyytn.cfuncB()"
1000 loops, best of 3: 512 usec per loop

所以在这种情况下,速度提升了 30 倍。


另外,顺便提一下,你可以通过把 arr.tostring() 替换成 arr.data.as_chars[:len(arr)],并将 a 的类型设为 bytes,再节省一些微秒。

撰写回答