Python中的信号处理和日志记录

11 投票
2 回答
6973 浏览
提问于 2025-04-16 09:26

关于日志模块的文档提到:

如果你在使用信号模块实现异步信号处理程序时,可能无法在这些处理程序中使用日志记录。这是因为线程模块中的锁的实现并不总是可以重新进入,因此不能在这样的信号处理程序中调用。

这意味着你不应该在信号处理程序直接或间接调用日志记录。如果偶尔这样做,程序可能会陷入一种只有通过强制终止(kill -9)才能解决的状态。

我现在面临的一个重要问题是:当其他线程在主线程处理信号时调用日志方法,是否也会出现这个锁的问题?

2 个回答

2

GIL(全局解释器锁)让任何Python代码不能同时运行,所以从技术上讲,主线程在其他线程运行时无法处理信号。虽然看起来好像可以,但实际上只有一个大锁,允许一次只有一个Python线程在运行。

我猜测,信号和线程的问题在于,信号通常是由中断引起的,这种中断可以随时发生。所以我想Python会停止当前的操作,然后调用信号处理函数。这个时候可能已经有一个锁被占用了,如果日志记录再去请求锁,就会出现死锁。在某些实现中,这样是可以的,因为这个锁可以被多次锁定(可重入),但在其他实现中,只有一个锁。

希望其他人能对此进行补充。

9

在UNIX编程中,信号处理需要特别注意。只有一些特定的POSIX C函数被认为是可重入的,也就是说,它们可以在POSIX信号处理程序中被调用。IEEE标准1003.1列出了118个可重入的UNIX函数,你可以在https://www.opengroup.org/找到这些函数(需要登录)。

不过,Python的信号是异步的:signal模块对此有进一步说明:

虽然从Python用户的角度来看,信号处理程序是异步调用的,但它们只能在Python解释器的“原子”指令之间发生。这意味着,在进行一些长时间计算的过程中(比如在大文本上进行正则表达式匹配),如果有信号到达,可能会被延迟一段时间。

在这种情况下,Python中的信号会被推迟,直到全局解释器锁(GIL)空闲

回到你的问题。,只要在信号处理函数中使用可重入的函数,就不会有问题。如果日志记录只在线程中使用,那就不会有任何问题。

撰写回答