我可以进一步优化这个 Cython 代码片段(包含 NumPy 和一个字符串)吗?

Can I further optimize this Cython code snippet (contains NumPy and a string)?

我是 Cython 的初学者,但我一直在学习一些入门教程以尝试优化一些 Python 代码。我已经为所有变量定义了类型,但 cython --annotate 显示的 Python 交互比预期的多得多。这是输出,对于那些无法查看图像的人,还有代码:

+148: cdef int[:] get_hp_lengths(str seq):
+149:     hp_lens_buf = np.zeros(len(seq), dtype=np.intc)
+150:     cdef int[:] hp_lens = hp_lens_buf
 151:     cdef Py_ssize_t start, stop
 152: 
+153:     for start in range(len(seq)):
+154:         for stop in range(start+1, len(seq)):
+155:             if seq[stop] != seq[start]:
+156:                 hp_lens[start] = stop - start
+157:                 break
+158:     if len(seq):
+159:         hp_lens[-1] += 1
+160:     return hp_lens

是不是因为我用的是numpy,应该已经够快了吧?看起来 str 也引起了 Python 交互。有没有更好的数据类型可以使用,因为我先验地不知道 seq 的长度,但它只包含 'ACGT'?基本上,我想验证我是否遵循了最佳实践,没有比这更快的方法来实现了。

大多数 python 交互是由于 len 是一个 python 函数并且您多次调用它。但是,它只需要计算一次。您可以通过 boundscheck 编译器指令禁用对 hp_lens[start] 的索引检查来进一步减少 python 交互:

from cython cimport boundscheck

@boundscheck(False)
cdef int[:] get_hp_lengths(str seq):
    cdef int seq_len = len(seq)
    hp_lens_buf = np.zeros(seq_len, dtype=np.intc)
    cdef int[:] hp_lens = hp_lens_buf
    cdef Py_ssize_t start, stop

    for start in range(seq_len):
        for stop in range(start+1, seq_len):
            if seq[stop] != seq[start]:
                hp_lens[start] = stop - start
                break
    if seq_len > 0:
        hp_lens[-1] += 1
    return hp_lens

这可能是您可以用代码做的最好的事情了:

  • 将 python 字符串替换为 c_string
  • 用连续的缓冲区替换内存缓冲区
  • ??
  • 盈利!

这是编辑后的代码

cimport cython
@cython.boundscheck(False)
cdef int[::1] get_hp_lengths(const unsigned char[::1] seq):
    cdef int seq_len = seq.shape[0]
    cdef int[::1] hp_lens = np.zeros(seq_len, dtype= np.intc)
    cdef size_t start, stop
    for start in range(seq_len):
        for stop in range(start+1, seq_len):
            if seq[stop] != seq[start]:
                hp_lens[start] = stop - start
                break
    if seq_len > 0:
        hp_lens[seq_len] += 1
    return hp_lens

产生以下内容html

看起来不错!