Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/27.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 试图使QProcess与队列一起工作_Python_Queue_Pyqt5_Qprocess_Pyside2 - Fatal编程技术网

Python 试图使QProcess与队列一起工作

Python 试图使QProcess与队列一起工作,python,queue,pyqt5,qprocess,pyside2,Python,Queue,Pyqt5,Qprocess,Pyside2,我正在尝试使用一个队列运行多个进程,并使用QProcess获取所有进程的输出,但我遇到了几个问题。我使用QSpinBox将max进程设置为同时运行,我可以在主线程中使一切正常工作,或者如果我在QObject中使用进程运行循环,但我无法使它在QThread中正常工作。 我知道没有必要在QProcess中使用线程,但在循环中我几乎没有选择。当在主线程中运行时,它会暂时冻结,直到进程开始,我希望它运行得更平稳。 除非我使用类似于_process.waitForFinished的东西,否则我在尝试运行Q

我正在尝试使用一个队列运行多个进程,并使用QProcess获取所有进程的输出,但我遇到了几个问题。我使用QSpinBox将max进程设置为同时运行,我可以在主线程中使一切正常工作,或者如果我在QObject中使用进程运行循环,但我无法使它在QThread中正常工作。 我知道没有必要在QProcess中使用线程,但在循环中我几乎没有选择。当在主线程中运行时,它会暂时冻结,直到进程开始,我希望它运行得更平稳。 除非我使用类似于_process.waitForFinished的东西,否则我在尝试运行QThread中的进程时只会出现错误,但问题是进程一次只运行一个。 有人有什么建议让它正常工作吗?我目前正在使用Pyside2,但Pyside2或PyQt5的答案就可以了。谢谢

import queue
import sys
from PySide2.QtCore import QProcess, QTextCodec, QThread, Qt
from PySide2.QtWidgets import QApplication, QWidget, QSpinBox, \
    QPushButton, QVBoxLayout

class Window(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        self.setAttribute(Qt.WA_DeleteOnClose, True)
        self.queue = queue.Queue()
        layout = QVBoxLayout(self)
        self.startBtn = QPushButton('Start', clicked=self.addToQueue)
        self.spinBox = QSpinBox(value=3)
        layout.addWidget(self.spinBox)
        layout.addWidget(self.startBtn)
        self.taskList = ['my.exe -value','my.exe -value','my.exe -value','my.exe -value',
                         'my.exe -value','my.exe -value','my.exe -value','my.exe -value']

    def addToQueue(self):
        for i in self.taskList:
            self.queue.put(i)
        self.sendToThread()

    def sendToThread(self):
        vals = {'max': self.spinBox.value()}
        self.taskThread = TaskThread(self.queue, vals)
        self.taskThread.start()

    def closeEvent(self, event):
        event.accept()

class TaskThread(QThread):
    def __init__(self, queue=None, vals=None, parent=None):
        QThread.__init__(self, parent)
        self.queue = queue
        self.vals = vals
        self.maxProcs = self.vals.get('max')
        self.procCount = 0

    def run(self):
        self.start_procs()

    def start_procs(self):
        while not self.queue.empty() and self.procCount < self.maxProcs:
            cmd = self.queue.get()
            _process = QProcess(self)
            _process.setProcessChannelMode(QProcess.MergedChannels)
            self.codec = QTextCodec.codecForLocale()
            self._decoder_stdout = self.codec.makeDecoder()
            _process.readyReadStandardOutput.connect(lambda process=_process: self._ready_read_standard_output(process))
            _process.started.connect(self.procStarted)
            _process.finished.connect(self.procFinished)
            _process.finished.connect(self.decreaseCount)
            _process.finished.connect(self.start_procs)
            _process.start(cmd)
            self.procCount += 1

    def _ready_read_standard_output(self, process):
        self.out = process.readAllStandardOutput()
        self.text = self._decoder_stdout.toUnicode(self.out)
        print(self.text)

    def decreaseCount(self):
        if self.procCount <= 0:
            pass
        else:
            self.procCount -= 1

    def procStarted(self):
        print('started')

    def procFinished(self):
        print('finished')

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = Window()
    window.resize(200, 100)
    window.show()
    sys.exit(app.exec_())

启动流程时,并不意味着它已启动,因为它可能存在执行问题,因此在第一次启动时,最好等待流程启动或无法启动以下流程,满足正在运行的进程数小于最大值、不再执行任务或尚未启动的要求

另一方面,我还实现了停止任务,这意味着不再添加任务,但停止之前正在执行的任务将继续执行

如果将maxvalue更改为较低的值,则在满足条件之前不会抛出更多任务

考虑到上述情况,没有必要使用线程

import queue
from PySide2 import QtCore, QtGui, QtWidgets

class TaskManager(QtCore.QObject):
    messageChanged = QtCore.Signal(str)
    numbersTaskRunningChanged = QtCore.Signal(int)

    def __init__(self, parent=None):
        super(TaskManager, self).__init__(parent)
        self._max_task = 1
        self._queue = queue.Queue()
        self._numbers_task_running = 0
        self._running = False

    def setMaxTask(self, max_task):
        self._max_task = max_task
        if self._running:
            self.call_task()

    def maxTask(self):
        return self._max_task

    def appendTask(self, task):
        self._queue.put(task)
        self.call_task()

    def start(self):
        self._running = True
        self.call_task()

    def stop(self):
        self._running = False

    def call_task(self):
        if self._numbers_task_running < self.maxTask() and not self._queue.empty() and self._running:
            cmd = self._queue.get()
            process = QtCore.QProcess(self)
            process.setProcessChannelMode(QtCore.QProcess.MergedChannels)
            process.readyReadStandardOutput.connect(self.on_readyReadStandardOutput)
            process.finished.connect(self.on_finished)
            process.started.connect(self.on_started)
            process.errorOccurred.connect(self.on_errorOccurred)
            process.start(cmd)

    def on_readyReadStandardOutput(self):
        codec = QtCore.QTextCodec.codecForLocale()
        decoder_stdout = codec.makeDecoder()
        process = self.sender()
        text = decoder_stdout.toUnicode(process.readAllStandardOutput())
        self.messageChanged.emit(text)

    def on_errorOccurred(self, error):
        process = self.sender()
        print("error: ", error, "-", " ".join([process.program()] + process.arguments()))
        self.call_task()

    def on_finished(self):
        process = self.sender()
        self._numbers_task_running -= 1
        self.numbersTaskRunningChanged.emit(self._numbers_task_running)
        self.call_task()

    def on_started(self):
        process = self.sender()
        print("started: ", " ".join([process.program()] + process.arguments()))
        self._numbers_task_running += 1
        self.numbersTaskRunningChanged.emit(self._numbers_task_running)
        self.call_task()

class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(Widget, self).__init__(parent)
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
        manager = TaskManager(self)
        task_list = # ...
        for task in task_list:
            manager.appendTask(task)

        button_start = QtWidgets.QPushButton("Start", clicked=manager.start)
        button_stop = QtWidgets.QPushButton("Stop", clicked=manager.stop)
        label = QtWidgets.QLabel("0", alignment=QtCore.Qt.AlignCenter)
        manager.numbersTaskRunningChanged.connect(label.setNum)
        spinBox = QtWidgets.QSpinBox()
        spinBox.valueChanged.connect(manager.setMaxTask)
        spinBox.setValue(3)
        textEdit = QtWidgets.QTextEdit()
        manager.messageChanged.connect(textEdit.append)

        lay = QtWidgets.QVBoxLayout(self)
        lay.addWidget(spinBox)
        lay.addWidget(button_start)
        lay.addWidget(button_stop)
        lay.addWidget(label)
        lay.addWidget(textEdit)

if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = Widget()
    w.show()
    sys.exit(app.exec_())

据我所知,你有n个任务,你只想在瞬间执行我的任务,所以如果一个任务完成了,它必须被另一个任务替换。我是对的?。在一个数字示例中,假设您有50个任务,并且您希望执行最多6个任务,然后将执行前6项任务,如果其中一项任务完成,则应将其替换为剩余的另一项任务。另一方面,假设您最多设置了6项任务,然后使用QSlider将任务更改为4项,那么您是否应该终止2项任务,或者在达到新的最大任务之前不添加任务?对不起,我刚看到你的答复。我正在尝试在队列中异步运行多个任务。因此,如果我有10个任务,并且我将spinbox设置为4,那么10个任务中的4个将运行,并且新任务将随着其他任务的完成而启动,但是一次运行的任务数量不会超过设置的数量。非常感谢。它工作得很好。我尝试使用QThread的主要原因是为了避免启动进程的初始延迟,但这其实没什么大不了的。我很高兴你的方法也摆脱了while循环。我很难让它在没有额外循环的情况下正常工作。非常感谢你的帮助!