【发布时间】:2018-11-24 19:06:57
【问题描述】:
我正在尝试使用队列运行多个进程并使用QProcess 获取所有进程的输出,但我遇到了几个问题。我正在使用QSpinBox 来设置同时运行的最大进程,并且我可以在主线程中让一切正常工作,或者如果我使用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_())
【问题讨论】:
-
据我了解,你有n个任务,你只想在瞬间执行我的任务,所以如果一个任务完成了,它必须被另一个替换。我是对的?。举一个数字示例,假设您有 50 个任务,并且您希望最多执行 6 个任务,那么前 6 个任务将被执行,如果其中一个任务完成,则应该被其余任务中的另一个替换.
-
另一方面,假设您最多设置了 6 个任务,然后使用 QSlider 更改为 4 个任务,那么您应该杀死 2 个任务还是在达到新的最大值之前不添加任务?
-
抱歉,刚刚看到你的回复。我正在尝试在队列中异步运行多个任务。因此,如果我有 10 个任务,并且我将 spinbox 设置为 4,那么 10 个任务中的 4 个将运行,并且新任务随着其他任务的完成而开始,但一次运行的任务数量永远不会超过设定的数量。
标签: python queue pyqt5 qprocess pyside2