Spec-Zone.ru › Python 3.12

Подпроцессы

Исходный код: Lib/asyncio/subprocess.py, Lib/asyncio/base_subprocess.py

В этом разделе описаны высокоуровневые API asyncio с async/await для создания и управления подпроцессами.

Вот пример того, как asyncio может выполнить команду оболочки и получить её результат:

import asyncio

async def run(cmd):
    proc = await asyncio.create_subprocess_shell(
        cmd,
        stdout=asyncio.subprocess.PIPE,
        stderr=asyncio.subprocess.PIPE)

    stdout, stderr = await proc.communicate()

    print(f'[{cmd!r} exited with {proc.returncode}]')
    if stdout:
        print(f'[stdout]\n{stdout.decode()}')
    if stderr:
        print(f'[stderr]\n{stderr.decode()}')

asyncio.run(run('ls /zzz'))

будет напечатано:

['ls /zzz' exited with 1]
[stderr]
ls: /zzz: No such file or directory

Поскольку все функции asyncio для работы с подпроцессами являются асинхронными, а asyncio предоставляет множество инструментов для работы с такими функциями, легко выполнять и отслеживать несколько подпроцессов параллельно. Действительно, совсем несложно изменить приведённый выше пример так, чтобы одновременно выполнялось несколько команд:

async def main():
    await asyncio.gather(
        run('ls /zzz'),
        run('sleep 1; echo "hello"'))

asyncio.run(main())

См. также подраздел Примеры.

Создание подпроцессов

async asyncio.create_subprocess_exec(program, *args, stdin=None, stdout=None, stderr=None, limit=None, **kwds)

Создать подпроцесс.

Аргумент limit задаёт предел буфера для обёрток StreamReader для Process.stdout и Process.stderr (если аргументам stdout и stderr передано значение subprocess.PIPE).

Возвращает экземпляр Process.

Другие параметры описаны в документации loop.subprocess_exec().

Изменено в версии 3.10: Удалён параметр loop.

async asyncio.create_subprocess_shell(cmd, stdin=None, stdout=None, stderr=None, limit=None, **kwds)

Выполнить команду оболочки cmd.

Аргумент limit задаёт предел буфера для обёрток StreamReader для Process.stdout и Process.stderr (если аргументам stdout и stderr передано значение subprocess.PIPE).

Возвращает экземпляр Process.

Другие параметры описаны в документации loop.subprocess_shell().

Важно

Приложение должно обеспечить правильное экранирование всех пробельных символов и специальных символов, чтобы избежать уязвимостей, связанных с инъекцией в оболочку. Функцию shlex.quote() можно использовать для правильного экранирования пробельных символов и специальных символов оболочки в строках, которые будут использоваться для создания команд оболочки.

Изменено в версии 3.10: Удалён параметр loop.

Примечание

Подпроцессы доступны в Windows, если используется ProactorEventLoop. Подробности см. в разделе Поддержка подпроцессов в Windows.

См. также

В asyncio также доступны следующие низкоуровневые API для работы с подпроцессами: loop.subprocess_exec(), loop.subprocess_shell(), loop.connect_read_pipe(), loop.connect_write_pipe(), а также транспорты подпроцессов и протоколы подпроцессов.

Константы

asyncio.subprocess.PIPE

Можно передать параметрам stdin, stdout или stderr.

Если аргументу stdin передано значение PIPE, атрибут Process.stdin будет указывать на экземпляр StreamWriter.

Если аргументам stdout или stderr передано значение PIPE, атрибуты Process.stdout и Process.stderr будут указывать на экземпляры StreamReader.

asyncio.subprocess.STDOUT

Специальное значение, которое можно использовать как аргумент stderr. Оно указывает, что стандартный поток ошибок следует перенаправить в стандартный поток вывода.

asyncio.subprocess.DEVNULL

Специальное значение, которое можно использовать как аргумент stdin, stdout или stderr в функциях создания процессов. Оно указывает, что для соответствующего потока подпроцесса будет использоваться специальный файл os.devnull.

Взаимодействие с подпроцессами

Функции create_subprocess_exec() и create_subprocess_shell() возвращают экземпляры класса Process. Process — это высокоуровневая обёртка, которая позволяет взаимодействовать с подпроцессами и отслеживать их завершение.

class asyncio.subprocess.Process

Объект-обёртка для процессов ОС, созданных функциями create_subprocess_exec() и create_subprocess_shell().

Этот класс разработан с API, похожим на API класса subprocess.Popen, но имеет несколько существенных отличий:

  • в отличие от Popen, у экземпляров Process нет аналога метода poll();
  • методы communicate() и wait() не имеют параметра timeout: используйте функцию wait_for();
  • метод Process.wait() является асинхронным, тогда как метод subprocess.Popen.wait() реализован как блокирующий активный цикл ожидания;
  • параметр universal_newlines не поддерживается.

Этот класс не является потокобезопасным.

См. также раздел Подпроцессы и потоки.

async wait()

Дождаться завершения дочернего процесса.

Установить и вернуть атрибут returncode.

Примечание

При использовании stdout=PIPE или stderr=PIPE этот метод может привести к взаимоблокировке, если дочерний процесс создаёт так много вывода, что блокируется в ожидании освобождения места в буфере канала ОС. Чтобы избежать этого, при использовании каналов применяйте метод communicate().

async communicate(input=None)

Взаимодействовать с процессом:

  1. отправить данные в stdin (если input не равен None);
  2. закрыть stdin;
  3. читать данные из stdout и stderr, пока не будет достигнут EOF;
  4. дождаться завершения процесса.

Необязательный аргумент input — это данные (объект bytes), которые будут отправлены дочернему процессу.

Возвращает кортеж (stdout_data, stderr_data).

Если при записи input в stdin возникает исключение BrokenPipeError или ConnectionResetError, оно игнорируется. Это происходит, когда процесс завершается до того, как все данные записаны в stdin.

Чтобы отправлять данные в stdin процесса, его необходимо создать с помощью stdin=PIPE. Аналогично, чтобы получить в кортеже результата что-либо, кроме None, процесс нужно создать с аргументами stdout=PIPE и/или stderr=PIPE.

Обратите внимание: прочитанные данные буферизуются в памяти, поэтому не используйте этот метод, если объём данных велик или не ограничен.

Изменено в версии 3.12: stdin также закрывается при input=None.

send_signal(signal)

Отправить сигнал signal дочернему процессу.

Примечание

В Windows SIGTERM является псевдонимом для terminate(). Процессам, запущенным с параметром creationflags, содержащим CREATE_NEW_PROCESS_GROUP, можно отправлять CTRL_C_EVENT и CTRL_BREAK_EVENT.

terminate()

Остановить дочерний процесс.

В системах POSIX этот метод отправляет дочернему процессу сигнал SIGTERM.

В Windows для остановки дочернего процесса вызывается функция API Win32 TerminateProcess().

kill()

Убить дочерний процесс.

В системах POSIX этот метод отправляет дочернему процессу сигнал SIGKILL.

В Windows этот метод является псевдонимом для terminate().

stdin

Поток стандартного ввода (StreamWriter) или None, если процесс создан с помощью stdin=None.

stdout

Поток стандартного вывода (StreamReader) или None, если процесс создан с помощью stdout=None.

stderr

Поток стандартных ошибок (StreamReader) или None, если процесс создан с помощью stderr=None.

Предупреждение

Используйте метод communicate(), а не process.stdin.write(), await process.stdout.read() или await process.stderr.read(). Это позволяет избежать взаимоблокировок, возникающих, когда чтение или запись в поток приостанавливается и блокирует дочерний процесс.

pid

Идентификационный номер процесса (PID).

Обратите внимание: для процессов, созданных функцией create_subprocess_shell(), этот атрибут содержит PID запущенной оболочки.

returncode

Код возврата процесса после его завершения.

Значение None означает, что процесс ещё не завершился.

Отрицательное значение -N означает, что дочерний процесс был завершён сигналом N (только POSIX).

Подпроцессы и потоки

Стандартный цикл событий asyncio по умолчанию поддерживает запуск подпроцессов из разных потоков.

В Windows подпроцессы поддерживаются только в ProactorEventLoop (используется по умолчанию); SelectorEventLoop не поддерживает подпроцессы.

В UNIX для ожидания завершения подпроцессов используются наблюдатели дочерних процессов; дополнительную информацию см. в разделе Наблюдатели процессов.

Изменено в версии 3.8: В UNIX для запуска подпроцессов из разных потоков без ограничений теперь используется ThreadedChildWatcher.

Запуск подпроцесса при неактивном текущем наблюдателе дочерних процессов вызывает исключение RuntimeError.

Обратите внимание, что альтернативные реализации циклов событий могут иметь собственные ограничения; обратитесь к их документации.

См. также

Раздел Параллельное выполнение и многопоточность в asyncio.

Примеры

Пример использования класса Process для управления подпроцессом и класса StreamReader для чтения из его стандартного потока вывода.

Подпроцесс создаётся функцией create_subprocess_exec():

import asyncio
import sys

async def get_date():
    code = 'import datetime; print(datetime.datetime.now())'

    # Create the subprocess; redirect the standard output
    # into a pipe.
    proc = await asyncio.create_subprocess_exec(
        sys.executable, '-c', code,
        stdout=asyncio.subprocess.PIPE)

    # Read one line of output.
    data = await proc.stdout.readline()
    line = data.decode('ascii').rstrip()

    # Wait for the subprocess exit.
    await proc.wait()
    return line

date = asyncio.run(get_date())
print(f"Current date: {date}")

См. также тот же пример, написанный с использованием низкоуровневых API.

© 2001–2024 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.12/library/asyncio-subprocess.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API