2017-02-15 1 views
1

У меня есть многопоточная программа Python, как показано ниже. Если я нажму ctrl + c в течение 5 секунд (приблизительно), он войдет в Исключение KeyboardInterrupt.Выход потоков Python с ctrl-c в Python

Выполнение кода более 15 секунд не отвечает на ctrl + c. Если я нажимаю ctrl + c через 15 секунд, он не работает. Это не бросает исключение KeyboardInterrupt. Что может быть причиной ? Я тестировал это на Linux.

#!/usr/bin/python 

import os, sys, threading, time 

class Worker(threading.Thread): 
    def __init__(self): 
    threading.Thread.__init__(self) 
    # A flag to notify the thread that it should finish up and exit 
    self.kill_received = False 

    def run(self): 
     while not self.kill_received: 
      self.do_something() 

    def do_something(self): 
     [i*i for i in range(10000)] 
     time.sleep(1) 

def main(args): 

    threads = [] 
    for i in range(10): 
     t = Worker() 
     threads.append(t) 
     t.start() 

    while len(threads) > 0: 
     try: 
      # Join all threads using a timeout so it doesn't block 
      # Filter out threads which have been joined or are None 
      threads = [t.join(1) for t in threads if t is not None and t.isAlive()] 
     except KeyboardInterrupt: 
      print "Ctrl-c received! Sending kill to threads..." 
      for t in threads: 
       t.kill_received = True 

if __name__ == '__main__': 
    main(sys.argv) 

ответ

1

После первого исполнения

threads = [t.join(1) for t in threads if t is not None and t.isAlive()] 

ваша переменная threads содержит

[None, None, None, None, None, None, None, None, None, None] 

после второго исполнения, та же переменная threads содержит:

[] 

На данный момент len(threads) > 0 False, и вы выходите из цикла while. Ваш скрипт все еще запущен, так как у вас есть еще 10 потоков, но поскольку вы больше не находитесь в своем блоке try/except (чтобы поймать KeyboardInterrupt), вы не можете прекратить использование Ctrl + C

Добавьте несколько отпечатков на свой сценарий, чтобы увидеть, что я описал:

#!/usr/bin/python 

import os, sys, threading, time 

class Worker(threading.Thread): 
    def __init__(self): 
    threading.Thread.__init__(self) 
    # A flag to notify the thread that it should finish up and exit 
    self.kill_received = False 

    def run(self): 
     while not self.kill_received: 
      self.do_something() 

    def do_something(self): 
     [i*i for i in range(10000)] 
     time.sleep(1) 

def main(args): 

    threads = [] 
    for i in range(10): 
     t = Worker() 
     threads.append(t) 
     t.start() 
     print('thread {} started'.format(i)) 

    while len(threads) > 0: 
     print('Before joining') 
     try: 
      # Join all threads using a timeout so it doesn't block 
      # Filter out threads which have been joined or are None 
      threads = [t.join(1) for t in threads if t is not None and t.isAlive()] 
      print('After join() on threads: threads={}'.format(threads)) 

     except KeyboardInterrupt: 
      print("Ctrl-c received! Sending kill to threads...") 
      for t in threads: 
       t.kill_received = True 
    print('main() execution is now finished...') 

if __name__ == '__main__': 
    main(sys.argv) 

и результат:

$ python thread_test.py 
thread 0 started 
thread 1 started 
thread 2 started 
thread 3 started 
thread 4 started 
thread 5 started 
thread 6 started 
thread 7 started 
thread 8 started 
thread 9 started 
Before joining 
After join() on threads: threads=[None, None, None, None, None, None, None, None, None, None] 
Before joining 
After join() on threads: threads=[] 
main() execution is now finished... 

на самом деле, Ctrl + C не перестает работать через 15 секунд, но после 10 или 11 секунд. Это время, необходимое для создания и запуска 10 потоков (менее секунды) и для выполнения объединения (1) для каждого потока (около 10 секунд).

Подсказка от the doc:

Как присоединиться() всегда возвращает None, вы не должны вызывать IsAlive() после того, как присоединиться к(), чтобы решить, будет ли произошло тайм-аут - если поток все еще жив, присоединиться() время ожидания вызова.

Смежные вопросы