简体   繁体   English

无法使用 Ctrl-C 终止 Python 脚本

[英]Cannot kill Python script with Ctrl-C

I am testing Python threading with the following script:我正在使用以下脚本测试 Python 线程:

import threading

class FirstThread (threading.Thread):
    def run (self):
        while True:
            print 'first'

class SecondThread (threading.Thread):
    def run (self):
        while True:
            print 'second'

FirstThread().start()
SecondThread().start()

This is running in Python 2.7 on Kubuntu 11.10.这是在 Kubuntu 11.10 上的 Python 2.7 中运行的。 Ctrl + C will not kill it. Ctrl + C不会杀死它。 I also tried adding a handler for system signals, but that did not help:我还尝试为系统信号添加处理程序,但这没有帮助:

import signal 
import sys
def signal_handler(signal, frame):
    sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)

To kill the process I am killing it by PID after sending the program to the background with Ctrl + Z , which isn't being ignored.为了杀死进程,我在使用Ctrl + Z将程序发送到后台后通过 PID 杀死它,这不会被忽略。 Why is Ctrl + C being ignored so persistently?为什么Ctrl + C如此持久地被忽略? How can I resolve this?我该如何解决这个问题?

Ctrl + C terminates the main thread, but because your threads aren't in daemon mode, they keep running, and that keeps the process alive. Ctrl + C终止主线程,但是由于您的线程未处于守护程序模式,它们会继续运行,从而使进程保持活动状态。 We can make them daemons:我们可以让它们成为守护进程:

f = FirstThread()
f.daemon = True
f.start()
s = SecondThread()
s.daemon = True
s.start()

But then there's another problem - once the main thread has started your threads, there's nothing else for it to do.但是还有另一个问题——一旦主线程启动了你的线程,它就没有什么可做的了。 So it exits, and the threads are destroyed instantly.所以它退出了,线程立即被销毁。 So let's keep the main thread alive:所以让我们保持主线程活着:

import time
while True:
    time.sleep(1)

Now it will keep print 'first' and 'second' until you hit Ctrl + C .现在它将保持打印“第一”和“第二”,直到您点击Ctrl + C

Edit: as commenters have pointed out, the daemon threads may not get a chance to clean up things like temporary files.编辑:正如评论者指出的那样,守护线程可能没有机会清理临时文件之类的东西。 If you need that, then catch the KeyboardInterrupt on the main thread and have it co-ordinate cleanup and shutdown.如果需要,则在主线程上捕获KeyboardInterrupt并让它协调清理和关闭。 But in many cases, letting daemon threads die suddenly is probably good enough.但在很多情况下,让守护线程突然死掉可能就足够了。

KeyboardInterrupt 和信号只有进程(即主线程)才能看到...看看Ctrl-c 即 KeyboardInterrupt 以杀死 python 中的线程

I think it's best to call join() on your threads when you expect them to die.我认为当您希望线程死亡时,最好在线程上调用join() I've taken the liberty to make the change your loops to end (you can add whatever cleanup needs are required to there as well).我冒昧地将您的循环更改为结束(您也可以在那里添加所需的任何清理需求)。 The variable die is checked on each pass and when it's True , the program exits.每次通过时都会检查变量die ,当它为True时,程序退出。

import threading
import time

class MyThread (threading.Thread):
    die = False
    def __init__(self, name):
        threading.Thread.__init__(self)
        self.name = name

    def run (self):
        while not self.die:
            time.sleep(1)
            print (self.name)

    def join(self):
        self.die = True
        super().join()

if __name__ == '__main__':
    f = MyThread('first')
    f.start()
    s = MyThread('second')
    s.start()
    try:
        while True:
            time.sleep(2)
    except KeyboardInterrupt:
        f.join()
        s.join()

An improved version of @Thomas K's answer : @Thomas K 答案的改进版本:

  • Defining an assistant function is_any_thread_alive() according to this gist , which can terminates the main() automatically.根据这个要点定义一个辅助函数is_any_thread_alive() ,它可以自动终止main()

Example codes:示例代码:

import threading

def job1():
    ...

def job2():
    ...

def is_any_thread_alive(threads):
    return True in [t.is_alive() for t in threads]

if __name__ == "__main__":
    ...
    t1 = threading.Thread(target=job1,daemon=True)
    t2 = threading.Thread(target=job2,daemon=True)
    t1.start()
    t2.start()

    while is_any_thread_alive([t1,t2]):
        time.sleep(0)

One simple 'gotcha' to beware of, are you sure CAPS LOCK isn't on?要提防一个简单的“陷阱”,您确定CAPS LOCK没有打开吗?

I was running a Python script in the Thonny IDE on a Pi4.我在 Pi4 上的 Thonny IDE 中运行 Python 脚本。 With CAPS LOCK on, Ctrl + Shift + C is passed to the keyboard buffer, not Ctrl + C .启用CAPS LOCK后, Ctrl + Shift + C被传递到键盘缓冲区,而不是Ctrl + C

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM