问题描述
我具有以下cython功能。
01:
+02: cdef int count_char_in_x(unicode x,Py_UCS4 c):
03: cdef:
+04: int count = 0
05: Py_UCS4 x_k
06:
+07: for x_k in x: ## Yellow
+08: if x_k == c:
+09: count+=1
10:
+11: return count
第7行没有正确优化。
带注释的HTML代码被扩展为:
+07: for x_k in x: ## Yellow
if (unlikely(__pyx_v_x == Py_None)) {
PyErr_SetString(PyExc_TypeError,"'NoneType' is not iterable");
__PYX_ERR(0,8,__pyx_L1_error)
}
__Pyx_INCREF(__pyx_v_x);
__pyx_t_1 = __pyx_v_x;
__pyx_t_6 = __Pyx_init_unicode_iteration(__pyx_t_1,(&__pyx_t_3),(&__pyx_t_4),(&__pyx_t_5)); if (unlikely(__pyx_t_6 == ((int)-1))) __PYX_ERR(0,__pyx_L1_error)
for (__pyx_t_7 = 0; __pyx_t_7 < __pyx_t_3; __pyx_t_7++) {
__pyx_t_2 = __pyx_t_7;
__pyx_v_x_k = __Pyx_PyUnicode_READ(__pyx_t_5,__pyx_t_4,__pyx_t_2);
-
有关如何改善此问题的任何提示?
-
我认为可以编写一个cdef / cpdef函数,在运行时完全避免Python None类型检查。关于如何做到这一点的任何想法?
解决方法
生成的C代码对我来说看起来不错。整个循环是一个完整的for循环(即,它不依赖于调用Python方法__iter__
和__next__
)。
__Pyx_PyUnicode_READ
is translated pretty directly to PyUnicode_READ
(略微取决于您使用的Python版本)。 PyUnicode_READ
是一个C语言宏,它是as close to a direct array access as you can get。
这可能和所获得的一样好。使用bytes
而不是unicode
可能会有所改善(前提是您要处理ASCII字符)。您可能只是考虑是否真的值得重新实现unicode.count
。
如果它是常规的def
函数,则可以将x
声明为unicode not None
,以在循环之前删除None
检查。那可能会有所不同。但是,正如@ead指出的,cdef
函数不支持。 def
函数调用的开销可能会比None
检查的开销稍大,但是如果需要的话,应该计时一下。