2017-02-15 85 views
1

我有如下的Python多線程程序。如果我在5秒鐘內(大約)按ctrl + c,它會進入KeyboardInterrupt異常Python線程在Python中按ctrl-c退出

運行超過15秒的代碼未能響應ctrl + c。如果我在15秒後按ctrl + c,它不起作用。這是不扔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是假的,你離開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秒)並在每個線程上執行join(1)(大約10秒)所需的時間。

the doc

提示:

由於join()方法總是返回None,你必須調用的IsAlive()之後加入()來決定超時是否發生了 - 如果線程還活着,連接()通話超時。