Spec-Zone.ru › Python 3.13

Подпроцессы

Исходный код: 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 для 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=None, **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(). CTRL_C_EVENT и CTRL_BREAK_EVENT можно отправлять процессам, запущенным с параметром creationflags, включающим CREATE_NEW_PROCESS_GROUP.

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 означает, что процесс ещё не завершился.

Отрицательное значение -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–2025 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.13/library/asyncio-subprocess.html

Spec-Zone.ru

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