Как я могу запустить внешнюю команду асинхронно из Python?



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



Я прочитал этот пост:




вызов внешней команды в Python




затем я пошел и сделал некоторые испытания, и это выглядит как os.system() будет делать эту работу при условии, что я использую & в конце команды, так что я не придется ждать его возвращения. Что я интересно, если это правильный способ сделать такую вещь? Я пытался commands.call() но это не будет работать для меня, потому что он блокирует на внешние команды.



пожалуйста, дайте мне знать, если вы используете os.system() для этого желательно, или если я должен попробовать другой маршрут.

697   7  

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

    Ничего не найдено.