2015-07-03 55 views
1

我需要调用外部程序N次数。我想同时做到这一点。所以我的策略到目前为止已经开始N QProcesses并保持已开始和已完成的计数。 (所以我可以弄清楚他们什么时候都完成了)。运行若干组QProcess'彼此相连

但是,外部程序占用了一点RAM,所以我不想在任何时候更多的4个并行进程。

这是什么策略?

我不认为信号/插槽足以实现这一目标(我想不出一种不是高度复杂的方法)......也许我可以用一个队列做些什么?

如何确保我一次只能运行4个进程? 我怎么才能找出所有N进程终于完成?

(答案为pyside/PyQt的优选的,但C++是OK)

回答

2

证明的概念:

.h文件

#ifndef CPROCESSRUNNER_H 
#define CPROCESSRUNNER_H 

#include <QObject> 
#include <QQueue> 

class QProcess; 

class CProcessRunner : public QObject 
{ 
    Q_OBJECT 
    Q_PROPERTY(int processCount READ processCount WRITE setProcessCount) 
public: 
    explicit CProcessRunner(QObject *parent = 0); 
    ~CProcessRunner(); 

    void addProcess(const QString& program); 

    int processCount() const; 

public slots: 
    void setProcessCount(int arg); 

private slots: 
    void startFreeProcesses(); 

private: 
    int getActiveProcessCount() const; 

    QQueue<QProcess*> m_processes; 
    int m_processCount; 
}; 

#endif // CPROCESSRUNNER_H 

CPP文件

#include "CProcessRunner.h" 
#include <QProcess> 
CProcessRunner::CProcessRunner(QObject *parent) 
    : QObject(parent) 
    , m_processCount(0) 
{ 

} 

CProcessRunner::~CProcessRunner() 
{ 

} 

void CProcessRunner::addProcess(const QString& program) 
{ 
    QProcess* pProcess = new QProcess(this); 
    pProcess->setObjectName(program); 
    m_processes.enqueue(pProcess); 
    startFreeProcesses(); 
} 

int CProcessRunner::processCount() const 
{ 
    return m_processCount; 
} 

void CProcessRunner::setProcessCount(int arg) 
{ 
    m_processCount = arg; 
} 

void CProcessRunner::startFreeProcesses() 
{ 
    while (!m_processes.isEmpty() && (getActiveProcessCount() < m_processCount)) { 
     QProcess* pProcess = m_processes.dequeue(); 
     connect(pProcess, SIGNAL(finished(int)), this, SLOT(startFreeProcesses())); 
     connect(pProcess, SIGNAL(finished(int)), pProcess, SLOT(deleteLater())); 

     pProcess->start(pProcess->objectName()); 
     pProcess->waitForStarted(-1); 
    } 
} 

int CProcessRunner::getActiveProcessCount() const 
{ 
    int result = 0; 
    foreach (QProcess* pProcess, findChildren<QProcess*>()) { 
     if (pProcess->state() == QProcess::Running) { 
      result++; 
     } 
    } 
    return result; 
} 
+0

,这看起来像一个非常良好的开端。我们如何知道所有流程何时完成? 我想在调用函数中,你可以把'while(process_runner.getActiveProcessCount()> 0)类似的东西继续下去... ...会是最好的吗? – jramm

+0

您可以在startFreeProcesses中检入getActiveProcessCount等于零。每一个,完成后,你将chech已经完成所有的过程。 – Milovidov

+0

'm_processCount'应该重命名为'm_maxAsyncProcessCount',或类似的东西。除此之外,看起来不错,并且完成了工作! – phyatt

0

对于参考,这里是我目前使用Pyside的实现。 我希望能够捕获每个进程的输出并将其传递(例如用于显示QTextEdit或类似内容)。为此,我为每个进程分配一个数字,并将它的stdout和stderr连接到插槽,然后发送消息和进程位置。 我不是我目前执行的该功能所折服,但在这里有云:

class ProcessRunner(QtCore.QObject): 
''' 
Runs N processes in groups of M 
'''  

singleProcessFinished = QtCore.Signal() 
error = QtCore.Signal(tuple) #(process number, message) 
message = QtCore.Signal(tuple) #(process number, message) 

def __init__(self, maxProcesses=4, parent=None): 
    super(ProcessRunner, self).__init__(parent) 
    self.processQueue = Queue.Queue() 
    self.maxProcesses = maxProcesses 
    self.activeProcessCount = 0 

    self._processNumber = 0 

def addProcess(self, program, args): 
    ''' 
    Add a process to the process queue 

    Args: 

    program (str): String of program path and arguments, separated by one or more spaces  
    ''' 
    self._processNumber += 1 
    if self._processNumber == self.maxProcesses: 
    self._processNumber = 0 


    proc = QtCore.QProcess(self) 
    proc.readyReadStandardError.connect(lambda pos=self._processNumber, process=proc: self.emit_error(pos, proc)) 
    proc.readyReadStandardOutput.connect(lambda pos=self._processNumber, process=proc: self.emit_output(pos, proc)) 
    self.processQueue.put((proc, program, args)) 
    self.startFreeProcesses() 

def startFreeProcesses(self): 
    ''' 
    Starts all waiting processes up to a maximum of self.maxProcesses 
    ''' 
    while (not self.processQueue.empty()) and (self.activeProcessCount < self.maxProcesses): 
    proc, program, args = self.processQueue.get() 
    proc.finished.connect(self.startFreeProcesses) 
    proc.finished.connect(proc.deleteLater) 
    proc.finished.connect(self.singleProcessFinished.emit) 
    proc.finished.connect(self._decreaseActiveProcessCount) 

    proc.start(program, args) 
    proc.waitForStarted(-1) 
    self._increaseActiveProcessCount() 

def _decreaseActiveProcessCount(self): 
    self.activeProcessCount -= 1 

def _increaseActiveProcessCount(self): 
    self.activeProcessCount += 1 

def emit_error(self, pos, proc):  
    self.error.emit(pos, str(proc.readAllStandardError())) 

def emit_error(self, pos, proc):  
    self.error.emit(pos, str(proc.readAllStandardOutput())) 
+0

我认为,那种不好的方式是手工计算自由过程。这些信息可以在运行时从所有子进程中获取和计算。在你的情况下,你会得到免费的进程数量非常重要。如果这将在完成信号和_decreaseActiveProcessCount函数之间进行,则计数错误。 – Milovidov