如何停止QThread "gracefully"?



我得到了一些帮助来做下面的代码。但是我需要从Worker线程中的这个循环中跳出来,这样当我退出应用程序时,它就不会崩溃。此刻,当我退出应用程序时,QThread仍在运行。如果我使用break语句,它可以工作,但是我不能再搜索主机,因为循环已经完全关闭了。我试了好几种方法做这件事,但都不成功。我是编程新手。

class Worker(QThread):
found = Signal(str)
notFound = Signal(str)
def __init__(self):
QThread.__init__(self)
self.queue = Queue()
def run(self):
while True:
hostname = self.queue.get()
output_text = collect_host_status(hostname)
for i in output_text:
if "not found" in i:
self.notFound.emit(i.replace(" not found", ""))
else:
self.found.emit(i)
def lookUp(self, hostname):
self.queue.put(hostname)

class MainWindow(QMainWindow):
def __init__(self):
# ...
self.ui.pushButton_2.clicked.connect(self.buttonclicked)
self.thread = Worker()
self.thread.found.connect(self.ui.textEdit_2.append)
self.thread.notFound.connect(self.ui.textEdit_3.append)
self.thread.start()
def buttonclicked(self):
if self.ui.textEdit.toPlainText():
self.thread.lookUp(self.ui.textEdit.toPlainText())

收集主机状态的代码:

def get_brss_host_status(host):

host = host.lower()
api_url = 'https://some.system.with/api/'
host_search = 'status/host/{}?format=json'.format(host)

r = requests.get(api_url + host_search, auth=(loc_brss_user, loc_brss_passwd))
request_output = r.text
if request_output == '{"error":"Not Found","full_error":"Not Found"}':
host2 = host.upper()
host_search2 = 'status/host/{}?format=json'.format(host2)
r2 = requests.get(api_url + host_search2, auth=(loc_brss_user, loc_brss_passwd))
request_output2 = r2.text
# print('Debug request_output2', request_output2)
if request_output and request_output2 == '{"error":"Not Found","full_error":"Not Found"}':
output_string = host + " not found"
else:
output_string = host2
else:
output_string = host

return output_string

def collect_host_status(hosts):

hosts_list = list(hosts.split("n"))

status_list = []
for i in hosts_list:

host = get_brss_host_status(i)
status_list.append(host)

return status_list

基本解决方案,正如@ekhumoro在评论中建议的那样,是在while循环中使用一个简单的标志,这将确保一旦循环重新开始,如果不遵守条件,它就会退出。

在两个重要的方面应该小心使用:

  • 使用Queue的基本get()使周期等待不确定;
  • 如果发生网络问题(临时网络问题等),示例中的函数(网络请求)可能会延迟一段时间;

要正确解决这些问题,应做以下修改:

  • get()应该使用超时,这样即使没有请求正在排队,它也允许退出循环;作为替代方案,您可以取消设置"正在运行"。标志,将任何东西添加到队列并在继续之前检查标志:这确保您不必等待队列get()超时;
  • 网络请求也应该有一个最小超时;
  • 他们应该从线程单独完成,而不是分组,这样线程可以退出,如果请求的主机列表太大,你想在做查找时退出;
from queue import Queue, Empty
class Worker(QThread):
found = Signal(str)
notFound = Signal(str)
def __init__(self):
QThread.__init__(self)
self.queue = Queue()
def run(self):
self.keepRunning = True
while self.keepRunning:
hostList = self.queue.get()
if not self.keepRunning:
break
# otherwise:
# try:
#     hostList = self.queue.get(timeout=1)
# except Empty:
#     continue
for hostname in hostList.splitlines():
if not self.keepRunning:
break
if hostname:
output_text = get_brss_host_status(hostname)
if output_text is None:
continue
if "not found" in output_text:
self.notFound.emit(output_text.replace(" not found", ""))
else:
self.found.emit(output_text)
def stop(self):
self.keepRunning = False
self.queue.put(None)
def lookUp(self, hostname):
self.queue.put(hostname)

get_brss_host_status中,修改如下:

def get_brss_host_status(host):

host = host.lower()
api_url = 'https://some.system.with/api/'
host_search = 'status/host/{}?format=json'.format(host)

try:
r = requests.get(api_url + host_search, 
auth=(loc_brss_user, loc_brss_passwd), 
timeout=1)
except Timeout:
return
# ...

最新更新