Spec-Zone.ru › Python 3.14

Подпроцессы

Исходный код: 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=65536, **kwds)

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

Аргумент limit задаёт предел буфера для оболочек StreamReader для stdout и 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=65536, **kwds)

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

Аргумент limit задаёт предел буфера для оболочек StreamReader для stdout и 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 для остановки дочернего процесса вызывается функция Win32 API 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 означает, что процесс ещё не завершился.

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

Для процессов, созданных с помощью create_subprocess_shell(), код возврата отражает код завершения самой оболочки (например, /bin/sh), которая может преобразовывать сигналы в такие коды, как 128+N. Подробности см. в документации оболочки (например, в разделе «Код завершения» руководства Bash).

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

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

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

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

См. также

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

Примеры

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

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

import asyncio
import sys

async def get_date():
    code = 'import datetime as dt; print(dt.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 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.14/library/asyncio-subprocess.html

Spec-Zone.ru

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