【发布时间】:2018-04-15 08:37:25
【问题描述】:
我在文件保存操作期间遇到了一些问题,GUI 在需要一些时间的过程中冻结,我很想了解这是为什么。
我已经按照similar question 上的Schollii's wonderful answer 的说明进行操作,但是我一定缺少一些东西,因为我无法让 GUI 像我预期的那样运行。
以下示例不可运行,因为它仅显示相关部分,但希望它足以让讨论继续进行。基本上我有一个生成一些大数据的主应用程序类,我需要将其保存为 HDF5 格式,但这需要一些时间。为了让 GUI 响应,主类创建一个 Saver 类的对象和一个 QThread 来进行实际的数据保存(使用 moveToThread)。
这段代码的输出几乎是我所期望的(即我看到一条消息,“保存线程”的线程 ID 与“主”线程不同)所以我知道正在创建另一个线程。数据也已成功保存,因此该部分工作正常。
然而,在实际数据保存期间(可能需要几分钟),GUI 冻结并在 Windows 上显示“无响应”。关于出了什么问题的任何线索?
运行中的标准输出:
outer thread "main" (#15108)
<__main__.Saver object at 0x0000027BEEFF3678> running SaveThread
Saving data from thread "saving_thread" (#13624)
代码示例:
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QThread, pyqtSignal, pyqtSlot, QObject
class MyApp(QtWidgets.QMainWindow, MyAppDesign.Ui_MainWindow):
def save_file(self):
self.save_name, _ = QtWidgets.\
QFileDialog.getSaveFileName(self)
QThread.currentThread().setObjectName('main')
outer_thread_name = QThread.currentThread().objectName()
outer_thread_id = int(QThread.currentThreadId())
# print debug info about main app thread:
print('outer thread "{}" (#{})'.format(outer_thread_name,
outer_thread_id))
# Create worker and thread to save the data
self.saver = Saver(self.data,
self.save_name,
self.compressionSlider.value())
self.save_thread = QThread()
self.save_thread.setObjectName('saving_thread')
self.saver.moveToThread(self.save_thread)
# Connect signals
self.saver.sig_done.connect(self.on_saver_done)
self.saver.sig_msg.connect(print)
self.save_thread.started.connect(self.saver.save_data)
self.save_thread.start())
@pyqtSlot(str)
def on_saver_done(self, filename):
print('Finished saving {}'.format(filename))
''' End Class '''
class Saver(QObject):
sig_done = pyqtSignal(str) # worker id: emitted at end of work()
sig_msg = pyqtSignal(str) # message to be shown to user
def __init__(self, data_to_save, filename, compression_level):
super().__init__()
self.data = data_to_save
self.filename = filename
self.compression_level = compression_level
@pyqtSlot()
def save_data(self):
thread_name = QThread.currentThread().objectName()
thread_id = int(QThread.currentThreadId())
self.sig_msg.emit('Saving data '
'from thread "{}" (#{})'.format(thread_name,
thread_id))
print(self, "running SaveThread")
h5f = h5py.File(self.filename, 'w')
h5f.create_dataset('data',
data=self.data,
compression='gzip',
compression_opts=self.compression_level)
h5f.close()
self.sig_done.emit(self.filename)
''' End Class '''
【问题讨论】:
标签: python multithreading pyqt pyqt5 python-multithreading