【问题标题】:Why does Cython keep making python objects instead of c? [duplicate]为什么 Cython 一直在制作 python 对象而不是 c? [复制]
【发布时间】:2022-02-09 02:18:05
【问题描述】:

我正在尝试学习 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 速度运行? 该函数返回一个 python 字典,因此我认为我不能返回任何 c 数据类型。我在这里可能错了。

感谢您的帮助!

【问题讨论】:

  • 我将不得不详细研究它,但它是很好的学习材料。谢谢@ead!!

标签: numpy cython


【解决方案1】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多