如何在不使用.terminate()

时间:2017-10-06 17:24:24

标签: python qt numpy pyqt qthread

我正在制作一个GUI应用程序,允许执行一些冗长的NumPy操作,我想让用户能够在中途取消操作。

我能找到一种方法来中断数值运算的唯一方法就是发出一个QThread.terminate();但是根据Qt docs,我们不鼓励使用它。

这是一个功能最少的代码示例。

from PyQt5 import QtWidgets, QtCore
import numpy as np
import sys
import time
from timeit import default_timer as timer


class ProcessorThread(QtCore.QThread):
    finished = QtCore.pyqtSignal(object)

    def __init__(self, callback):
        super().__init__()
        self.finished.connect(callback)

    def run(self):
        print('in run method')
        matrix = np.linalg.inv(np.random.random(size=(10000, 10000)))
        print('matrix inversion complete')
        self.finished.emit(matrix)
        self.quit()


class MainDialog(QtWidgets.QDialog):

    def __init__(self):
        super().__init__()
        self.setWindowTitle('Example Threading')
        self.buttonBox =\
            QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Ok |
                                       QtWidgets.QDialogButtonBox.Cancel)

        self.buttonBox.accepted.connect(self.startThread)
        self.buttonBox.rejected.connect(self.reject)
        self.processingThread = None
        layout = QtWidgets.QVBoxLayout()
        layout.addWidget(self.buttonBox, alignment=QtCore.Qt.AlignHCenter)
        self.setLayout(layout)

    def startThread(self):
        print('starting thread')
        self.buttonBox.rejected.disconnect()
        self.buttonBox.rejected.connect(self.abortThread)
        self.processingThread = ProcessorThread(callback=self.threadFinished)
        self.processingThread.start()

    @QtCore.pyqtSlot(object)
    def threadFinished(self, resulting_matrix):
        print('thread finished')

    @QtCore.pyqtSlot()
    def abortThread(self):
        start_time = timer()
        print('received abort signal')
        print('trying to quit')
        self.processingThread.quit()
        while self.processingThread.isRunning():
            time.sleep(1)
            print(f'thread is still running {int(timer() - start_time)} seconds after cancel')
        print('thread has finally quit')


def main():
    app = QtWidgets.QApplication(sys.argv)
    window = MainDialog()
    window.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()

要演示此问题,请运行此代码,点击“确定”。 (开始计算),然后按“取消”,你会注意到尽管取消了取消,数字操作仍在继续。

以下是我运行时的打印输出:

starting thread
in run method
received abort signal
trying to quit
thread is still running 1 seconds after cancel
thread is still running 2 seconds after cancel
thread is still running 3 seconds after cancel
thread is still running 4 seconds after cancel
thread is still running 5 seconds after cancel
thread is still running 6 seconds after cancel
thread is still running 7 seconds after cancel
thread is still running 8 seconds after cancel
thread is still running 9 seconds after cancel
thread is still running 10 seconds after cancel
thread is still running 11 seconds after cancel
thread is still running 12 seconds after cancel
thread is still running 13 seconds after cancel
thread is still running 14 seconds after cancel
thread is still running 15 seconds after cancel
thread is still running 16 seconds after cancel
thread is still running 17 seconds after cancel
thread is still running 18 seconds after cancel
matrix inversion complete
thread is still running 19 seconds after cancel
thread has finally quit
thread finished

我的第一个想法是在一个单独的子进程中运行numpy操作,当我收到退出信号时,将signal.sigterm发送到该子进程;但在这一点上,我只是在猜测。

有什么建议吗?

0 个答案:

没有答案