Python 脚本无法 Ctrl-C 终止?三个妙招助你轻松解决!
2024-03-12 13:26:56
Python 脚本无法使用 Ctrl-C 终止?这里有三个解决方案!
身处程序员的世界中,当 Python 脚本拒绝响应 Ctrl-C 命令时,这可能会成为一个令人抓狂的时刻。但别担心,我有三个法宝可以解决这个问题,让你恢复对脚本的掌控。
罪魁祸首:GIL
Python 的全球解释器锁 (GIL) 是幕后黑手。它是一种机制,一次只允许一个线程执行 Python 代码。因此,当多个线程争夺 GIL 时,它们就会形成一个队列,导致 Ctrl-C 信号被无限期地阻塞。
解决方案 1:使用 multiprocessing
模块
multiprocessing
模块提供了另一种创建线程的方式,它可以绕过 GIL 的限制。使用它,每个进程都有自己的 GIL,从而允许多个线程同时运行。
解决方案 2:使用 signal.pthread_sigmask
signal.pthread_sigmask
函数可以暂时屏蔽 SIGINT 信号(Ctrl-C 触发),直到你准备好处理它。这提供了暂时忽略 Ctrl-C 的窗口期,直到你释放屏蔽。
解决方案 3:捕获 KeyboardInterrupt
异常
Python 在接收到 Ctrl-C 时会引发 KeyboardInterrupt
异常。你可以通过在代码中捕获此异常并进行适当处理来显式地处理 Ctrl-C。
示例代码
使用 signal.pthread_sigmask
import threading
import signal
def signal_handler(signal, frame):
print("Ctrl-C pressed")
signal.pthread_sigmask(signal.SIG_UNBLOCK, signal.SIGINT)
def first_thread():
while True:
print("first")
def second_thread():
while True:
print("second")
if __name__ == "__main__":
# 设置信号处理程序
signal.signal(signal.SIGINT, signal_handler)
# 屏蔽 SIGINT 信号
signal.pthread_sigmask(signal.SIG_BLOCK, signal.SIGINT)
# 启动线程
t1 = threading.Thread(target=first_thread)
t2 = threading.Thread(target=second_thread)
t1.start()
t2.start()
# 等待线程结束
t1.join()
t2.join()
常见问题解答
- 为什么我不能使用
time.sleep()
来模拟 Ctrl-C?
time.sleep()
会释放 GIL,但这并不能解除对 SIGINT 信号的阻塞。
- 使用
multiprocessing
模块的缺点是什么?
由于进程之间通信的开销,使用 multiprocessing
模块可能会降低性能。
- 捕获
KeyboardInterrupt
异常是否会阻止其他异常的引发?
不会,捕获 KeyboardInterrupt
异常只处理 Ctrl-C,而不影响其他异常。
- 为什么 GIL 存在?
GIL 旨在确保 Python 解释器在多线程环境中保持线程安全。
- GIL 有替代方案吗?
Python 3.11 中引入了多线程化(MPM),它是 GIL 的一种可选替代方案。