2014-03-30 97 views
3

我有一個python腳本,它將持續ping一些IP並將結果打印到屏幕上。 但我想通過按鍵終止腳本(理想情況下使用q鍵或通過ctrl c),然後爲所有線程終止。在Python中殺死所有線程

達到此目的的最佳方法是什麼?我的代碼如下...

import os 
import re 
import time 
import sys 
import subprocess 
import Queue 
import threading 

def screen_output(x, y, text): 
    sys.stdout.write("\x1b7\x1b[%d;%df%s\x1b8" % (x, y, text)) 
    sys.stdout.flush() 

class pingo: 

    def __init__(self,hosts): 
     self.q = Queue.Queue() 
     self.all_results = {} 
     self.hosts = hosts 

    def send_ping(self,q,ip): 
     self.q.put(self.record_results(ip)) 

    def record_results(self,ip): 
     ping_count = 0 

     host_results = { 
      "device" : None, 
      "sent_count" : 0, 
      "success_count": 0, 
      "fail_count": 0, 
      "failed_perc": 0, 
      "curr_status": None 
      } 


     while True: 
      rc = subprocess.call(['ping', '-c', '1', '-W', '1', ip], stdout=open('/dev/null', 'w'), stderr=open('/dev/null', 'w')) 
      ping_count += 1 

      # update stats 

      sent_count = host_results['sent_count'] 
      success_count = host_results['success_count'] 
      fail_count = host_results['fail_count'] 
      failed_perc = host_results['failed_perc'] 
      curr_status = host_results['curr_status'] 

      sent_count += 1 

      if rc == 0: 
       success_count += 1 
       curr_status = "Successful Response" 
      else: 
       fail_count += 1 
       curr_status = "Request Timed Out" 

      failed_perc = (fail_count/sent_count) * 100 

      host_results.update({'failed_perc': failed_perc, 'fail_count': fail_count, 'success_count': success_count, 'curr_status': curr_status, 'sent_count': sent_count}) 
      time.sleep(0.5) 
      self.all_results.update({ip:host_results}) 
      screen_output(0,0,self.all_results) 
     return True 

    def go(self): 
     for i in self.hosts: 
      t = threading.Thread(target=self.send_ping, args = (self.q,i)) 
      #t.daemon = True 
      t.start() 

p = pingo(["8.8.8.8"]) 
p.go() 

編輯:香港專業教育學院嘗試添加一個全球性的ALIVE標誌的建議,但是這仍然不能殺掉通過CRTL-C的線程。

import sys 
import subprocess 
import Queue 
import threading 
import signal 

def screen_output(x, y, text): 
    sys.stdout.write("\x1b7\x1b[%d;%df%s\x1b8" % (x, y, text)) 
    sys.stdout.flush() 

class pingo: 

    def __init__(self,hosts): 
     self.q = Queue.Queue() 
     self.all_results = {} 
     self.hosts = hosts 
     self.ALIVE = True 

    def signal_handler(self,signal, frame): 
     self.ALIVE = False 

    def send_ping(self,q,ip): 
     self.q.put(self.record_results(ip)) 

    def record_results(self,ip): 
     ping_count = 0 

     host_results = { 
      "device" : None, 
      "sent_count" : 0, 
      "success_count": 0, 
      "fail_count": 0, 
      "failed_perc": 0, 
      "curr_status": None 
      } 


     while self.ALIVE: 
      try: 
       rc = subprocess.call(['ping', '-c', '1', '-W', '1', ip], stdout=open('/dev/null', 'w'), stderr=open('/dev/null', 'w')) 
       ping_count += 1 

       # update stats 

       sent_count = host_results['sent_count'] 
       success_count = host_results['success_count'] 
       fail_count = host_results['fail_count'] 
       failed_perc = host_results['failed_perc'] 
       curr_status = host_results['curr_status'] 

       sent_count += 1 

       if rc == 0: 
        success_count += 1 
        curr_status = "Successful Response" 
       else: 
        fail_count += 1 
        curr_status = "Request Timed Out" 

       failed_perc = (fail_count/sent_count) * 100 

       host_results.update({'failed_perc': failed_perc, 'fail_count': fail_count, 'success_count': success_count, 'curr_status': curr_status, 'sent_count': sent_count}) 
       time.sleep(0.5) 
       self.all_results.update({ip:host_results}) 
       screen_output(0,0,self.all_results) 
      except KeyboardInterrupt: 
       signal.signal(signal.SIGINT, self.signal_handler) 
     return True 


    def go(self): 
     for i in self.hosts: 
      t = threading.Thread(target=self.send_ping, args = (self.q,i)) 
      #t.daemon = True 
      t.start() 

p = pingo(["8.8.8.8"]) 
p.go() 

回答

1

設置一個全局標誌ALIVE(或不一定是全局的,你可以使用字典或類屬性),結合SIGINT和改就認爲:

import signal 

ALIVE = True 

def signal_handler(signal, frame): 
    global ALIVE 
    ALIVE = False 

signal.signal(signal.SIGINT, signal_handler) 

,然後簡單地改變你的回到:

def record_results(self,ip): 
    # some code 
    while ALIVE: 
     # some code 

這樣它會優雅地退出(接收信號後的一段時間)。

+0

怎麼樣:**嘗試:**東西;和**除了KeyboardInterrupt:** – Marichyasana

+0

@Marichyasana它本質上是一樣的;你可以關閉除'KeyboardInterrupt'子句外的'全局ALIVE'。 – nodakai

+0

我試過你的建議,但這仍然沒有奏效。我更新了這個問題。 – felix001

0

這是Python中最常見的FAQ之一。基本上有兩種方法可以做到這一點。

  1. (優雅的方式)請參閱@ freakish的回答。
  2. (懶惰的方式)打開所有工作線程的「守護進程」標誌。看這個Q & A例如:Understanding Python daemon threads