2015-07-03 57 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