2010-09-21 6 views
3

Я пытаюсь использовать python для запуска команды в нескольких отдельных экземплярах терминала одновременно. Каков наилучший способ сделать это? Прямо сейчас я пытаюсь использовать модуль subprocess с popen, который работает для одной команды, но не множественный.Запуск нескольких процессов оболочки

Заранее спасибо.

Edit:

Вот что я делаю:

from subprocess import* 

Popen('ant -Dport='+str(5555)+ ' -Dhost='+GetIP()+ ' -DhubURL=http://192.168.1.113:4444 -Denvironment=*firefox launch-remote-control $HOME/selenium-grid-1.0.8', shell=True) 

Проблема для меня это запускает процесс Java в терминале, который я хочу, чтобы продолжать работать indefinatley. Во-вторых, я хочу запускать подобную команду несколько раз в нескольких разных процессах.

+1

Это также должно работать для нескольких, покажите свой код. – knitti

+1

Возможно, вам придется использовать 'Popen' для открытия терминала, например, gnome-terminal, и использовать флаги для отправки ему команды, которую вы хотите запустить. Единственная проблема с этим - я не могу понять, как заставить терминал оставаться открытым, как только он завершит назначенную команду. – sholsapp

+0

Почему он должен оставаться открытым? – knitti

ответ

1

Это должно оставаться открытым до тех пор, пока выполняется процесс. Если вы хотите запустить несколько одновременной установку, просто обернуть его в непроверенном коде thread

, но вы должны получить общее представление:


class PopenThread(threading.Thread): 

    def __init__(self, port): 
     threading.Thread.__init__(self) 
     self.port=port 

    def run(self): 
     Popen('ant -Dport='+str(self.port)+ ' -Dhost='+GetIP()+ 
       ' -DhubURL=http://192.168.1.113:4444' 
       ' -Denvironment=*firefox launch-remote-control' 
       ' $HOME/selenium-grid-1.0.8', shell=True) 

if '__main__'==__name__: 
    PopenThread(5555).start() 
    PopenThread(5556).start() 
    PopenThread(5557).start() 

EDIT: Метод двойной вилки описан здесь: https://stackoverflow.com/a/3765162/450517 Майком будет правильным способом запуска демона, т. е. долговременного процесса, который не будет связываться на stdio.

+1

Использование потоков здесь бессмысленно. 'Popen' не блокируется, поэтому вы получите тот же результат, который просто запускается' Popen' 3 раза в основном потоке. Проблема в том, что основная программа не ждет завершения какого-либо из процессов и, следовательно, (по крайней мере, по Linux) оставляет вокруг себя программы зомби. – tdelaney

+0

Не ясно из документов (https://docs.python.org/2/library/subprocess.html#subprocess.Popen), что он не блокируется, и поток в этом случае не повредит. Кроме того, они не должны быть зомби, но выполняются до тех пор, пока не будут завершены, а затем прекратятся независимо от запуска. – knitti

1

Простой ответ, который я могу придумать, чтобы иметь Python использовать Popen, чтобы запустить скрипт, похожий на:

gnome-terminal --window -e 'ant -Dport=5555 -Dhost=$IP1 -DhubURL=http://192.168.1.113:4444 -Denvironment=*firefox launch-remote-control $HOME/selenium-grid-1.0.8' & 
disown 
gnome-terminal --window -e 'ant -Dport=5555 -Dhost=$IP2 -DhubURL=http://192.168.1.113:4444 -Denvironment=*firefox launch-remote-control $HOME/selenium-grid-1.0.8' & 
disown 
# etc. ... 

Там есть способ полностью Python, чтобы сделать это, но это некрасиво, работает только на Unix-подобные ОС, и у меня нет времени писать код. В принципе, subprocess.Popen не поддерживает его, потому что предполагается, что вы хотите либо дождаться завершения подпроцесса, либо взаимодействовать с подпроцессом, либо контролировать подпроцесс. Он не поддерживает «просто запустить его и не беспокоить меня с ним когда-либо снова».

Таким образом, что делается в Unix-подобных операционных систем заключается в следующем:

  • Использование fork нереститься подпроцесс
  • Have что подпроцесс fork подпроцесс из своей собственной
  • У процесса внучат редирект I/O до /dev/null, а затем используйте одну из функций exec, чтобы запустить процесс, который вы действительно хотите запустить (возможно, сможете использовать Popen для этой части)
  • Ребенок p переходы.
  • Теперь нет никакой связи между дедушкой и внуком, поэтому, если внук прекратит вас, вы не получите сигнал SIGCHLD, и если бабушка и дедушка прекратят это, он не убьет всех внуков.

Возможно, я не в деталях, но это суть. Предполагается, что обследование (&) и disown ing в bash должно выполнить одно и то же.

+0

приятно видеть описанный здесь метод двойного форка – knitti

0

Вот плохая версия блокирующей очереди. Вы можете ухаживать за ней с помощью collection.deque или тому подобного, или даже любить с Twisted отложенными, или нет.Вшивый части включают в себя:

  • блокирование
  • убить сигналы не может распространяться вниз

сезона по вкусу!

import logging 
basicConfig = dict(level=logging.INFO, format='%(process)s %(asctime)s %(lineno)s %(levelname)s %(name)s %(message)s') 
logging.basicConfig(**basicConfig) 
logger = logging.getLogger({"__main__":None}.get(__name__, __name__)) 

import subprocess 

def wait_all(list_of_Popens,sleep_time): 
    """ blocking wait for all jobs to return. 

    Args: 
     list_of_Popens. list of possibly opened jobs 

    Returns: 
     list_of_Popens. list of possibly opened jobs 

    Side Effect: 
     block until all jobs complete. 
    """ 
    jobs = list_of_Popens 
    while None in [j.returncode for j in jobs]: 
     for j in jobs: j.poll() 
     logger.info("not all jobs complete, sleeping for %i", last_sleep) 
     time.sleep(sleep_time) 

    return jobs 


jobs = [subprocess.Popen('sleep 1'.split()) for x in range(10)] 
jobs = wait_all(jobs)