Как я могу запустить внешнюю команду асинхронно из Python?
мне нужно запустить команду асинхронно из скрипта Python. Под этим я подразумеваю, что я хочу, чтобы мой скрипт Python продолжал работать, пока внешняя команда выключается и делает все, что ей нужно.
Я прочитал этот пост:
вызов внешней команды в Python
затем я пошел и сделал некоторые испытания, и это выглядит как os.system() будет делать эту работу при условии, что я использую & в конце команды, так что я не придется ждать его возвращения. Что я интересно, если это правильный способ сделать такую вещь? Я пытался commands.call() но это не будет работать для меня, потому что он блокирует на внешние команды.
пожалуйста, дайте мне знать, если вы используете os.system() для этого желательно, или если я должен попробовать другой маршрут.
7 ответов:
подпроцесс.К popen делает именно то, что вы хотите.
from subprocess import Popen p = Popen(['watch', 'ls']) # something long running # ... do other stuff while subprocess is running p.terminate()(редактировать, чтобы завершить ответ из комментариев)
экземпляр Popen может делать различные другие вещи, как вы можете
poll()это, чтобы увидеть, если он все еще работает, и вы можетеcommunicate()С ним, чтобы отправить ему данные на stdin, и ждать его завершения.
Если вы хотите запустить много процессов параллельно, а затем обрабатывать их, когда они дают результаты, вы можете использовать опрос, как в следующем:
from subprocess import Popen, PIPE import time running_procs = [ Popen(['/usr/bin/my_cmd', '-i %s' % path], stdout=PIPE, stderr=PIPE) for path in '/tmp/file0 /tmp/file1 /tmp/file2'.split()] while running_procs: for proc in running_procs: retcode = proc.poll() if retcode is not None: # Process finished. running_procs.remove(proc) break else: # No process is done, wait a bit and check again. time.sleep(.1) continue # Here, `proc` has finished with return code `retcode` if retcode != 0: """Error handling.""" handle_results(proc.stdout)поток управления там немного запутан, потому что я пытаюсь сделать его маленьким-вы можете рефакторинг на свой вкус. : -)
это имеет преимущество обслуживать запросы раньше-отделки сперва. если вы называете
communicateна первом запущенном процессе, и это оказывается самым длинным, другие запущенные процессы будут сидеть там без дела, когда вы могли бы обрабатывать их результаты.
мне интересно, если это [os.system ()] является ли правильный способ достижения такой вещи?
нет.
os.system()Это не правильный способ. Вот почему все говорят использоватьsubprocess.для получения дополнительной информации прочитайте http://docs.python.org/library/os.html#os.system
модуль подпроцесса обеспечивает больше мощные средства для нереста новых процессы и получение их результаты; использование этого модуля является предпочтительнее использовать эту функцию. Использовать модуль подпроцесса. Проверять особенно замена старых Функции с модулем подпроцесса раздел.
с помощью pexpect [ http://www.noah.org/wiki/Pexpect ] с неблокирующими линиями чтения-это еще один способ сделать это. Pexpect решает проблемы взаимоблокировки, позволяет легко запускать процессы в фоновом режиме и дает простые способы иметь обратные вызовы, когда ваш процесс выплевывает предопределенные строки, и, как правило, делает взаимодействие с процессом намного проще.
У меня был хороший успех с asyncproc модуль, который прекрасно справляется с выводом из процессов. Например:
import os from asynproc import Process myProc = Process("myprogram.app") while True: # check to see if process has ended poll = myProc.wait(os.WNOHANG) if poll is not None: break # print any new output out = myProc.read() if out != "": print out
У меня такая же проблема при попытке подключиться к терминалу 3270 с помощью скриптового программного обеспечения s3270 в Python. Теперь я решаю проблему с подклассом процесса, который я нашел здесь:
http://code.activestate.com/recipes/440554/
и вот образец, взятый из файла:
def recv_some(p, t=.1, e=1, tr=5, stderr=0): if tr < 1: tr = 1 x = time.time()+t y = [] r = '' pr = p.recv if stderr: pr = p.recv_err while time.time() < x or r: r = pr() if r is None: if e: raise Exception(message) else: break elif r: y.append(r) else: time.sleep(max((x-time.time())/tr, 0)) return ''.join(y) def send_all(p, data): while len(data): sent = p.send(data) if sent is None: raise Exception(message) data = buffer(data, sent) if __name__ == '__main__': if sys.platform == 'win32': shell, commands, tail = ('cmd', ('dir /w', 'echo HELLO WORLD'), '\r\n') else: shell, commands, tail = ('sh', ('ls', 'echo HELLO WORLD'), '\n') a = Popen(shell, stdin=PIPE, stdout=PIPE) print recv_some(a), for cmd in commands: send_all(a, cmd + tail) print recv_some(a), send_all(a, 'exit' + tail) print recv_some(a, e=0) a.wait()
учитывая, что "мне не нужно ждать его возвращения", одним из самых простых решений будет следующее:
subprocess.Popen( \ [path_to_executable, arg1, arg2, ... argN], creationflags = subprocess.CREATE_NEW_CONSOLE, ).pidно... Из того, что я прочитал, это не "правильный способ выполнить такую вещь" из-за рисков безопасности, созданных
subprocess.CREATE_NEW_CONSOLEфлаг.ключевые вещи, которые происходят здесь является использование
subprocess.CREATE_NEW_CONSOLEдля создания новой консоли и.pid(возвращает идентификатор процесса, чтобы вы могли проверить программу позже, если хотите), чтобы не ждать завершения программы работа.
Comments