为什么 Cython 一直制作 python 个对象而不是 c?

Why does Cython keep making python objects instead of c?

我正在尝试学习 cython,我用 annotate=True 编译。

The basic manual中说:
如果一行是白色的,这意味着生成的代码不与 Python 交互,因此 运行 与普通 C 代码一样快。黄色越深,该行中的 Python 交互越多

然后我按照(据我所知)numpy in cython basic manual 说明编写了这段代码:

+14: cdef entropy(counts):
 15:     '''
 16:     INPUT: pandas table with counts as obsN
 17:     OUTPUT: general entropy
 18:     '''
+19:     cdef int l = counts.shape[0]
+20:     cdef np.ndarray probs = np.zeros(l, dtype=np.float)
+21:     cdef int totals = np.sum(counts)
+22:     probs = counts/totals
+23:     cdef np.ndarray plogp = np.zeros(l, dtype=np.float)
+24:     plogp = ( probs.T * (np.log(probs)) ).T
+25:     cdef float d = np.exp(-1 * np.sum(plogp))
+26:     cdef float relative_d = d / probs.shape[0]
 27: 
+28:     return {'d':d,
+29:             'relative_d':relative_d
 30:             }

其中所有行首的"+"在cython.debug.output.html中都是黄色文件。

我做错了什么?我怎样才能以 c 速度至少完成此功能的一部分 运行? 函数 returns 一个 python 字典,因此我认为我不能返回任何 c 数据类型。我这里可能是错的。

感谢您的帮助!

首先,Cython 不会重写 Numpy 函数,它只是像 CPython 那样调用它们。例如 np.zerosnp.sumnp.log 就是这种情况。使用 Cython 时,此类调用不会更快。如果您想要更快的代码,您可以使用普通循环在您的代码中 重新实现 它们。但是,这可能不会更快:一方面,Numpy 调用会引入开销(由于类型检查 AFAIK 仍然启用了 Cython、内部函数调用、包装器等),如果您使用小数组并且每个函数生成巨大的临时数组,这肯定很重要往往 read/write 很慢;另一方面,一些 Numpy 函数使用 highly-optimized 代码(如 BLAS 或 low-level SIMD 内在函数)。此外,Python 中的除法与 C 的行为方式不同。这就是为什么 Cython 提供标志 cython.cdivision 可以设置为 True(它是 False默认)。如果使用 Python 除法,Cython 会生成较慢的包装代码。最后,np.ndarray 是 CPython 类型并且表现如此,您可以使用 memoryviews 所以不要处理 Numpy 对象。

如果你想获得快速的代码,你当然需要使用memoryviewsloopsavoid创建临时数组 以及使用 多线程。此外,您可以在您的情况下使用 np.empty 而不是 np.zeros。除此之外,Numpy 转置效率不是很高,Numpy 没有解决这个问题。您可以实施 tiled-transposition 来加速它,但这对于有效实施它并非易事。 是一个 Numba 实现,当然可以轻松转换为 Cython 代码。将一些 cdef 放在 Python Numpy 代码上通常不会使其更快。