PyErr_CheckSignals 未拾取信号

ptb*_*ptb 5 c python signals python-c-api python-c-extension

我有一个 C 扩展,它实现了 LRU 缓存https://github.com/pbrady/fastcache。我最近注意到,在一个大量使用缓存的应用程序(SymPy)中,超时信号丢失,而应用程序继续运行。仅当使用我的 C 扩展而不是使用纯 Python LRU 缓存(即 functools.lru_cache)时才会发生这种情况https://github.com/pbrady/fastcache/issues/26

我在例程中添加了对 PyErr_CheckSignals() 的调用,信号丢失的频率降低了,但这种情况仍然会发生。请注意,在调用期间,缓存将调用 PyObject_Hash、PyDict_Get/Set/DelItem 和 PyObject_Call(在未命中的情况下)。

这是 SymPy 代码的相关片段(超时是一个整数):

def _timeout(self, function, timeout):
    def callback(x, y):
        signal.alarm(0)
        raise Skipped("Timeout")
    signal.signal(signal.SIGALRM, callback)
    signal.alarm(timeout)  # Set an alarm with a given timeout
    function()
    signal.alarm(0)  # Disable the alarm    enter code here
Run Code Online (Sandbox Code Playgroud)

有什么东西会覆盖信号吗?如果是这样,我该如何解决这个问题?

ptb*_*ptb 1

事实证明,这里并没有真正的神秘之处,但有点棘手。

除了调用 PyErr_CheckSignals() 之外,每当控制通过调用 PyObject_Hash、PyDict_Get/Set/DelItem 传递给解释器时,解释器都可以捕获信号。如果信号被解释器在这些函数之一中捕获,它将因回调函数而触发异常(并且信号将在处理后消失)。但是,我没有检查所有函数的返回值(即我知道我的参数是可散列的,所以我没有检查 PyDict_SetItem 的返回值),因此异常被忽略,程序继续执行,就好像信号没有一样发生了。

特别感谢Ondrej的谈话。