在Python中终止所有线程
我有一个Python脚本,它会不断地对一些IP地址进行ping操作,并把结果打印到屏幕上。 但是我想通过按一个键(最好是按“q”键或者使用“Ctrl+C”)来结束这个脚本,并且希望所有的线程都能被终止。
有什么好的方法可以实现这个呢?我的代码在下面...
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标志,按照建议的做法,但这仍然无法通过“Ctrl+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()
2 个回答
0
这是Python中最常见的问题之一。基本上有两种方法可以解决这个问题。
- (优雅的方法)可以参考@freakish的回答。
- (懒惰的方法)给所有的工作线程开启“守护线程”标志。可以看看这个问答作为例子:理解Python守护线程
2
设置一个全局标志 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
这样的话,当收到信号后,它会优雅地退出(会等一段时间后再退出)。