Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/287.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 多处理和GUI更新-Qprocess还是多处理?_Python_Multithreading_Qt_User Interface_Multiprocessing - Fatal编程技术网

Python 多处理和GUI更新-Qprocess还是多处理?

Python 多处理和GUI更新-Qprocess还是多处理?,python,multithreading,qt,user-interface,multiprocessing,Python,Multithreading,Qt,User Interface,Multiprocessing,在阅读了关于QProcesses和python的多处理模块的文献之后,我仍然很难在后台处理大型进程的过程中创建一个工作正常、响应迅速的GUI。 到目前为止,我已经提出了我的应用程序的这个简化版本,它仍然显示出与许多人描述的类似的问题 from PyQt4 import QtCore, QtGui import multiprocessing as mp import numpy as np import sys class Spectra: def __init__(self, spec

在阅读了关于QProcesses和python的多处理模块的文献之后,我仍然很难在后台处理大型进程的过程中创建一个工作正常、响应迅速的GUI。 到目前为止,我已经提出了我的应用程序的这个简化版本,它仍然显示出与许多人描述的类似的问题

from PyQt4 import QtCore, QtGui
import multiprocessing as mp
import numpy as np
import sys
class Spectra:
    def __init__(self, spectra_name, X, Y):
        self.spectra_name = spectra_name
        self.X = X
        self.Y = Y
        self.iteration = 0

    def complex_processing_on_spectra(self, pipe_conn):
        self.iteration += 1
        pipe_conn.send(self.iteration)

class Spectra_Tab(QtGui.QTabWidget):
    def __init__(self, parent, spectra):
        self.parent = parent
        self.spectra = spectra
        QtGui.QTabWidget.__init__(self, parent)

        self.treeWidget = QtGui.QTreeWidget(self)
        self.properties = QtGui.QTreeWidgetItem(self.treeWidget, ["Properties"])
        self.step = QtGui.QTreeWidgetItem(self.properties, ["Iteration #"])

        self.consumer, self.producer = mp.Pipe()
        # Make process associated with tab
        self.process = mp.Process(target=self.spectra.complex_processing_on_spectra, args=(self.producer,))

    def update_GUI(self, iteration):
        self.step.setText(1, str(iteration))

    def start_computation(self):
        self.process.start()
        while(True):
            message = self.consumer.recv()
            if message == 'done':
                break
            self.update_GUI(message)
        self.process.join()
        return

class MainWindow(QtGui.QMainWindow):
    def __init__(self, parent = None):
        QtGui.QMainWindow.__init__(self)

        self.setTabShape(QtGui.QTabWidget.Rounded)
        self.centralwidget = QtGui.QWidget(self)
        self.top_level_layout = QtGui.QGridLayout(self.centralwidget)

        self.tabWidget = QtGui.QTabWidget(self.centralwidget)
        self.top_level_layout.addWidget(self.tabWidget, 1, 0, 25, 25)

        process_button = QtGui.QPushButton("Process")
        self.top_level_layout.addWidget(process_button, 0, 1)
        QtCore.QObject.connect(process_button, QtCore.SIGNAL("clicked()"), self.process)

        self.setCentralWidget(self.centralwidget)
        self.centralwidget.setLayout(self.top_level_layout)

        # Open several files in loop from button - simplifed to one here
        X = np.arange(0.1200,.2)
        Y = np.arange(0.1200,.2)
        self.spectra = Spectra('name', X, Y)
        self.spectra_tab = Spectra_Tab(self.tabWidget, self.spectra)
        self.tabWidget.addTab(self.spectra_tab, 'name')

    def process(self):
        self.spectra_tab.start_computation()
        return

if __name__ == "__main__":
    app = QtGui.QApplication([])
    win = MainWindow()
    win.show()
    sys.exit(app.exec_())
如果您有依赖项,那么它应该完全能够执行。 目前,我有一个QThread版本的程序,可以处理信号和插槽;无论如何,我认为拥有使用所有计算机处理器的能力是很重要的,因为大多数用户都有~8个内核可供使用。因此,我想使用
multiprocessing
QProcess
es将此信号/插槽线程化方法扩展到多处理版本。
是否有人建议是否使用
QProcess
多处理
?虽然它们对我来说都很复杂,但QProcess似乎使用pyQt的论坛较少,所以我选择了多处理。由于我已经有信号/插槽与线程一起工作,使用QProcess会更简单吗

编辑:我应该按照建议添加这样的类吗

class My_Process(QtCore.QProcess):
    def __init__(self, spectra):
        QtCore.QProcess.__init__(self)
        self.spectra = spectra

    def worker(self):
        QtConcurrent.run(self.spectra, self.spectra.complex_processing_on_spectra)

    def run(self):
        QtCore.QObject.connect(self, QtCore.SIGNAL(QTimer.timeout()), self.worker)

QProcess
用于读取和写入管道(shell/cmd)。使用其中一个

  • 使用辅助函数创建一个类,并通过
    QtConcurrent.run(对象、方法、参数)
  • QTimer.timeout()
    与辅助函数连接

  • 尽管这个问题很老,而且已经得到了回答,但我想补充一些澄清:

    • AFAIK
      QtConcurrent
      在PyQt中不可用
    • C++中Qt的线程不同于pyqt或python线程。后者在运行时需要获取python的
      GIL
      (全局解释器锁),这实际上意味着python/pyqt线程之间没有真正的并发性
    Python线程可以保持gui的响应性,但您不会看到cpu限制任务的任何性能改进。我建议在处理与子进程通信的主进程上使用
    multiprocessing
    QThread
    。您可以在主(gui)和通信线程之间使用信号和插槽

    编辑:我只是遇到了同样的问题,并按照以下思路做了一些事情:

    from multiprocessing import Process, Queue
    from PyQt4 import QtCore
    from MyJob import job_function
    
    
    # Runner lives on the runner thread
    
    class Runner(QtCore.QObject):
        """
        Runs a job in a separate process and forwards messages from the job to the
        main thread through a pyqtSignal.
    
        """
    
        msg_from_job = QtCore.pyqtSignal(object)
    
        def __init__(self, start_signal):
            """
            :param start_signal: the pyqtSignal that starts the job
    
            """
            super(Runner, self).__init__()
            self.job_input = None
            start_signal.connect(self._run)
    
        def _run(self):
            queue = Queue()
            p = Process(target=job_function, args=(queue, self.job_input))
            p.start()
            while True:
                msg = queue.get()
                self.msg_from_job.emit(msg)
                if msg == 'done':
                    break
    
    
    # Things below live on the main thread
    
    def run_job(input):
        """ Call this to start a new job """
        runner.job_input = input
        runner_thread.start()
    
    
    def handle_msg(msg):
        print(msg)
        if msg == 'done':
            runner_thread.quit()
            runner_thread.wait()
    
    
    # Setup the OQ listener thread and move the OQ runner object to it
    runner_thread = QtCore.QThread()
    runner = Runner(start_signal=runner_thread.started)
    runner.msg_from_job.connect(handle_msg)
    runner.moveToThread(runner_thread)
    

    非常感谢你的帮助,但我不知道你的真正意思。我应该创建一个继承QProcess并从中生成线程的类吗?在我编辑的问题中,我尝试过这类课程。我不擅长Python,多年来用C++做QT。但我对你想要实现的目标有一点了解。据我所知,1
    QProcess
    允许您在应用程序中启动另一个进程(比如cmd.exe或firefox.exe或任何东西),您可以控制(启动、停止、写入、读取)它们。2.如果您试图在后台处理(或执行某些操作),请转到QThread、QTimer或QtConcurrent。所有这些都将在单独的进程中运行您的代码。所以你可以做以下一项。使用
    QThread
    。创建一个继承QThread并重载其run()方法的类。在里面写下复杂的光谱处理方法。或者可以在该类中使用Spectra对象。当迭代发生时发出信号。将此信号与将更新UI的插槽连接。B使用
    QTimer
    。将计时器的
    timeout()
    信号与
    update\u GUI()
    连接,间隔为n毫秒。C使用
    QtConcurrent
    。但这次你可以避免。我不确定它是否是一个可靠的API。谢谢@Muhammad,我现在明白了你所说的
    QProcess
    将不会运行,因为它只运行可执行文件。然而,
    QThreads
    和多线程只会在CPU上使用一个处理器,这不是真的吗?因此,当你有一个只使用多线程的程序时,如果你有一台现代计算机(~8个cpu核),它可能只能使用约15%的处理器?你可以通过使用线程来使用更多的cpu。如果您的应用程序有两个线程,系统策略将允许您使用两个内核。实际上,
    多核处理
    是管理线程的一个事实。Qt支持将线程移动到另一个线程中。因此,您可以实现一个关于如何管理线程、排列线程等的算法。当您有多个参数
    args=(queue,inp1,inp2)
    当我调用一个目标函数时,是否有人注意到一个“移位”,这类似于:
    def target\u fun(self,inp1,inp2,…)
    进程
    将其解释为
    args=(queue,inp2,inp3)
    如果我不将队列放在args中,队列会做什么?一切运行正常…@Hiatus我希望您现在已经解决了问题,但是看起来您是从类成员函数创建了一个进程,我不确定您是否能够做到这一点?奇怪的是,这种模式似乎在PyQt中有效,但在PySide中不起作用(1.2.4,在linux上)。在PySide中,连接到
    runner\u线程的
    \u run()
    方法启动后仍在主线程中运行。