那是赛通试图阻止你犯一些小错误。
首先,让我们回顾一下CPython中错误处理的工作原理:有一个全局错误状态(每个线程),它是在发生错误/异常时设置的。此状态包含有关异常类型、回溯等的信息。约定是,除了设置全局错误状态外,函数还通过一个特殊的返回值向失败发出信号,因此不必在每次函数调用后检查错误状态。
-
如果这个函数“知道”如何处理这个错误(例如,“except”-子句),那么它必须在继续之前清除全局错误状态。
-
重要的是:如果函数没有报告发生的错误,它应该清除错误状态,否则Python解释器处于不兼容状态,可能会发生细微的错误:例如cython
cdef
except?
取决于正确的错误状态(Cython的
except
this SO-answer
-
,cython负责全局状态:如果发生错误,则在函数返回默认值之前清除状态(并将警告写入标准错误)。
-
except 1
,函数的调用方必须负责清除错误状态。
FUNC_EVAL
-
ctypedef... (*FUNC_EVAL)(...) except 1
-
-函数。
try: ... except: ...
-函数,即
cdef RETCODE func_eval(int a,
int b,
void* func_data):
try:
(<object> func_data).func_eval(a, b)
except Exception:
return ERROR
return OKAY
try... except...
即使在没有引发异常的情况下也会增加开销。这是真的。但是,您已经调用了一些Python功能,因此这个额外的开销不会影响性能。
我的快速实验表明,如果在所谓的python功能中根本没有计算,您可能会损失高达30%(请参见答案附录中的实验)。但是上面是一个极端的情况,通常你会松得少得多,所以我不会尝试优化它,除非分析器显示它确实是一个问题。
ERROR=0
, so you can use the implementation detail, that Cython sets the result to
%%cython -a
cdef extern from *:
"""
typedef int (*FUN)(void);
void call(FUN f){
f();
}
"""
ctypedef int (*FUN)()
void call(FUN f)
def dummy():
pass
cdef int cython_handling():
dummy()
return 1
cdef int manual_handling():
try:
dummy()
except Exception:
return 0
return 1
def check_cython():
cdef int i
for i in range(1000):
call(cython_handling)
def check_manually():
cdef int i
for i in range(1000):
call(manual_handling)
%timeit check_cython()
# 21.6 µs ± 164 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit check_manually()
# 27 µs ± 493 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)