Скрипт Python Threading не запускается / работает неправильно

Я быстро написал этот пример сценария для stackru, поэтому проигнорируйте его функциональный аспект (моя версия выглядит намного лучше, чем эта), но:

from threading import Thread
from msvcrt import getch       #I'm using Windows by the way.
from time import sleep
import sys

def KeyEvent():
    while True:
        key = getch()
        if key.encode('hex') == '03': #^C
            y = raw_input("Are you sure you want to quit? (y/n): ").lower()
            if y == 'y':
                sys.exit(0)
            else: pass

def main():
    t = 0
    while True:
        print "The count is {0}".format(t)
        t +=1
        sleep(1)

if __name__ == "__main__":
    mainthread = Thread(target = main)
    kev = Thread(target = KeyEvent)

    mainthread.daemon = True
    kev.daemon = True

    mainthread.start()
    kev.start()

Предполагается, что этот скрипт должен запускать оба цикла одновременно, один считает в секундах, а другой проверяет ^C. Пожалуйста, не рекомендую использовать другой метод, потому что это пример.

Моя проблема в том, что скрипт просто не запускается. Он отображает "Счетчик 0" и выходит, но если я полностью опущу .daemon = True части, скрипт запускается, но не запускается sys.exit(0) правильно. Как я могу заставить этот скрипт работать правильно и выйти при появлении запроса?

2 ответа

Решение

Темы отмечены как daemon автоматически умирает, когда все остальные не-демонные потоки мертвы. В вашем случае основной поток умирает сразу после вызова start() в ваших двух потоках демонов, приводя процесс Python вместе с ним. То, что что-то сделано в вашей теме, зависит от времени и удачи.

sys.exit(0) не убивает потоки кроме основного потока. Вам нужен способ сообщить вашим темам, что пришло время остановиться. Один из способов сделать это - через объект Event.

Вы не должны использовать getch чтобы поймать Ctrl+C, попробуйте вместо этого использовать обработчик сигнала:

from threading import Thread
from threading import Event
from time import sleep
import signal

stop = Event()

def handler(signum, frame):
    y = raw_input("Are you sure you want to quit? (y/n): ").lower()
    if y == 'y':
        stop.set()

def main():
    t = 0
    while not stop.isSet():
        print "The count is {0}".format(t)
        t +=1
        sleep(1)

if __name__ == "__main__":
    signal.signal(signal.SIGINT, handler)

    mainthread = Thread(target = main)
    mainthread.start()

    while mainthread.is_alive():
        try:
            mainthread.join(timeout = 0.1)
        except IOError:
            pass #Gets thrown when we interrupt the join

У тебя две проблемы. Во-первых, ваша программа заканчивается слишком рано. Во-вторых, вы пытаетесь выйти из программы в вашем потоке KeyEvent.

Ваша программа завершается досрочно, потому что вы не держали основной поток. Ваш основной поток заканчивается сразу после вашего последнего выражения kev.start(), и ваши потоки демонов умирают вместе с ним.

Вам нужен механизм для бесконечного удержания основного потока (потому что вы ожидаете, что пользователь наберет "y" для выхода.) Есть несколько способов сделать это. Один добавить

mainthread.join()

до конца вашего кода.

Во-вторых, sys.exit(0) в вашем потоке KeyEvent, очевидно, не может завершить всю вашу программу. Пожалуйста, найдите ответ в следующем посте: почему sys.exit() не завершается при вызове внутри потока в Python?

Другие вопросы по тегам