0

次の UI を実装する必要があります。 - 「実行中の実験 1/X」というラベルの付いたウィンドウとボタンがあります。 - ウィンドウが読み込まれると、いくつかの実験が開始されます。実験は によって実行されos.systemsubprocess.Popenコンパイル済みの C++ プログラムにすぎません - 実験は厳密に次々と実行する必要があり、同時に実行することはできません (したがって、私は使用できませんsubprocess.Popen) - 実験の実行中はウィンドウをアクティブにする必要があり、ユーザーはボタンを押す - ボタンを押すと、実験が停止し (現在の実験が終了して停止するまで待つことができます)、ウィンドウが閉じます - すべての実験が終了すると、ウィンドウは自動的に閉じます

最初に で実験を実行しようとしましthreading.Threadたが、それでもウィンドウがブロックされました。だから私はに切り替えましたmultiprocessing.Process

class StoppableProcess(Process):
    def __init__(self, name, alg, proj, parent):
        Process.__init__(self)
        self.stop = False
        self.name = name
        self.alg = alg
        self.proj = proj
        self.parent = parent 

    def stop(self):
        self.stop = True

    def stopped(self):
        return self.stop

    def run(self):
        count = len([k for k in self.proj.values()])
        i = 1
        for p in self.proj.values():
            self.parent.label.setText("Running experiment " + str(i) + " / " + str(count))
            os.system("some command here")
            i += 1
            if self.stopped():
                break  
        self.parent.hide() 



class Runner(QDialog):
    def __init__(self, parent):
        QDialog.__init__(self, parent)
        self.layout = QVBoxLayout()
        self.label = QLabel("Running experiment 0 / 0")
        self.setWindowTitle("Running experiments")
        button = QPushButton("Break experiments")
        self.layout.addWidget(self.label)
        self.layout.addWidget(button)
        self.setLayout(self.layout)
        QObject.connect(button, SIGNAL("clicked()"), self.Break)

    def Run(self, name, alg, proj):
        self.thread = StoppableProcess(name, alg, proj, self)
        self.thread.start()
        self.show()
        self.thread.join()

    def Break(self):
        self.thread.stop()
        self.hide()

ただし、オブジェクトをピクルしてサブプロセスに渡す必要があるため、これはまったく機能しませんRunnerが、ピクルは失敗します。親引数を渡さないようにして、代わりに Qt シグナルを使用することを考えていましたが、もっと良い解決策があるのでしょうか?

4

1 に答える 1

1

まず第一に、実際にsubprocess.Popenバックグラウンド プロセスを開始し、その完了を待つことができます。ドキュメント、具体的にはpoll()メソッドを参照してください。プロセスが終了するまで UI イベント ループを実行します。

次に、通常、Python でスレッドを回避することをお勧めします。マルチプロセッシング モジュールは、Python で記述されたタスクを並列化したい場合に最も役立ちます。IMO、外部の子プロセスを起動するだけの場合は、サブプロセス モジュールを使用する方が簡単だと思います。

次の疑似コードは、この考え方を示しています。

experiments = [...]
process = None

def start_next_experiment():
    if not experiments:
        print "Done!"
    else:
        experiment = experiments.pop()
        process = subprocess.Popen(experiment)

def on_start_clicked():
    start_next_experiment()

def on_stop_clicked():
     # Clear the queue
    experiments = []

    # optional: Kill the process
    if process:
        process.terminate()

def on_idle():
    if process:
        # use e.g. a PyQT timer to run this method periodically
        process.poll()
        if process.returncode is not None:
            process = None
            start_next_experiment()
于 2013-09-28T15:04:58.333 に答える