QObject::killTimers 错误 QThread PyQt
我正在写一个脚本,用来批量下载一个图片论坛的图片,使用的是JSON/XML的接口。之前这个脚本完全是命令行模式,但最近我尝试用PyQt来做一个用户界面,虽然进展不错,但遇到了一个问题:线程阻塞,导致在调用工作线程时,界面变得无响应。所以,我想把原来的threading.Thread换成QThread,这样可以更好地管理(通过发出线程完成的信号来更新我的界面),但我似乎没有设置好。每次运行脚本时,线程都会提前结束。我是在Windows上运行,使用的是Python 2.7.2和PyQt4。
经过一些研究,我认为问题出在一个线程退出后,创建一个新线程,并从队列中传递一个新的元组。网上找到的所有结果都指向应用程序没有正常退出的问题。
Exception KeyError: KeyError(1188,) in <module 'threading' from 'C:\Python27\lib\threading.pyc'> ignored
QObject::killTimers: timers cannot be stopped from another thread
这是我收到的输出。
直接相关的代码:
md5_queue是一个空字典的队列,用于存放md5值和文件名,由Url_Download()填充。queue是一个包含文件名和网址的队列元组。
在crawler.py中:
num_conn = int(max_threads)
threads = []
for download in range(num_conn):
t = Url_Download(queue, md5_queue)
t.start()
threads.append(t)
在functions.py中(名字起得不好,我知道)的Url_Download()类:
class Url_Download(QThread):
file_finished = pyqtSignal(QString, int, name="fileFinished")
def __init__(self, dl_queue, md5_queue):
self.dl_queue = dl_queue
self.md5_queue = md5_queue
QThread.__init__(self)
def run(self):
while 1:
try:
count = 0
file_url, file_path, md5 = self.dl_queue.get_nowait()
file_extension = str(file_url)[-4:]
file_name = md5 + file_extension
while count < 3:
count +=1
fetch_url(file_url, file_path, md5)
if md5 == hash_sum(file_path):
self.md5_queue.put_nowait((md5, file_name))
self.file_finished.emit("Test!", 10)
break
if count > 3:
print 'File failed to download, {} might be corrupt.'.format(file_name)
qsize = self.dl_queue.qsize()
if qsize > 0:
print 'Count Remaining: ', qsize
except Queue.Empty:
raise SystemExit
except:
traceback.print_exc(file=sys.stderr)
sys.stderr.flush()
还有在GUI.py中的槽连接:
self.connect(self, SIGNAL("fileFinished(QString, int)"), self.handle_test, Qt.QueuedConnection)
代码的Git(测试分支):https://github.com/CirnoIsTheStrongest/BiriCrawler/tree/testing
请注意,这是我第一次尝试编写任何代码。如果这有问题,请告诉我。
1 个回答
1
感谢Avaris的帮助,我已经修正了连接指向我的Url_Download()实例。之前出现的问题在Windows上显示得很不清楚。在我的Linux虚拟机上,我得到了这个错误:
QThread: Destroyed while thread is still running
QThread: Destroyed while thread is still running
QThread: Destroyed while thread is still running
QThread: Destroyed while thread is still running
Segmentation fault
所以我认为问题还是因为我的图形界面(GUI)没有等线程完成任务就结束了。在GUI.py中引用了我的线程对象后,错误就不再出现了。我现在也终于可以从我的线程类中向GUI发送信号了。想查看其他更改的完整代码,可以在这里找到:Github页面,测试分支
在Crawler.py中
threads = []
for download in range(self.num_of_threads):
t = Url_Download(self.dl_queue, self.md5_queue, is_cli=True)
t.start()
threads.append(t)
for thread in threads:
thread.wait()
在GUI.py中
main = Crawler(gui_tags, gui_limit, gui_page, gui_booru, gui_savepath, gui_partype, gui_rating, max_threads)
self.threads = main.start_threads()
for thread in self.threads:
self.connect(thread, SIGNAL("fileFinished(QString, int)"), self.onFileFinished, Qt.QueuedConnection)
self.connect(thread, SIGNAL("allFinished()"), self.onAllFilesFinished, Qt.QueuedConnection)
在functions.py中
class Url_Download(QThread):
file_finished = pyqtSignal(QString, int, name="fileFinished")
def __init__(self, dl_queue, md5_queue, is_cli=False, parent=None):
QThread.__init__(self, parent)
self.exiting = False
self.dl_queue = dl_queue
self.md5_queue = md5_queue
self.is_cli = is_cli
def __del__(self):
self.exiting = True
def run(self):
while not self.exiting:
try:
count = 0
file_url, file_path, md5 = self.dl_queue.get_nowait()
file_extension = str(file_url)[-4:]
file_name = md5 + file_extension
while count < 3:
count +=1
fetch_url(file_url, file_path, md5)
if md5 == hash_sum(file_path):
self.md5_queue.put_nowait((md5, file_name))
self.file_finished.emit("Test!", 10)
break
if self.is_cli:
if count >= 3:
print 'File failed to download, {} might be corrupt.'.format(file_name)
qsize = self.dl_queue.qsize()
if qsize > 0:
print 'Count Remaining: ', qsize
except Queue.Empty:
self.__del__()
except:
traceback.print_exc(file=sys.stderr)
sys.stderr.flush()