2013-09-28 3 views
0

Мне нужно реализовать следующий интерфейс: - есть окно с меткой «running experience 1/X» и кнопка - Когда окно загружено, запускаются некоторые эксперименты , Эксперименты выполняются os.system из subprocess.Popen, они только что скомпилированные программы на С ++ - Эксперименты должны выполняться строго один за другим, а не одновременно (следовательно, я не могу использовать subprocess.Popen) - Окно должно быть активным, пока эксперименты и пользователь может нажать кнопку - Когда кнопка нажата, эксперименты прекращаются (мы можем просто подождать, пока текущий эксперимент не закончится и не остановится), и окно закрывается - Когда все эксперименты закончены, окно должно закрыть себяPython: немодальное окно с подпроцессами

Сначала я попытался запустить эксперименты в 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, но, может быть, есть лучшее решение?

ответ

1

Прежде всего, вы можете использовать subprocess.Popen для запуска фоновых процессов и дождаться их завершения. См. documentation, в частности метод poll(). Запустите цикл событий пользовательского интерфейса, пока процесс не завершится.

Во-вторых, обычно рекомендуется избегать потоков в 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() 

 Смежные вопросы

  • Нет связанных вопросов^_^