Spec-Zone.ru › Python 3.12

Подпроцессы

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

В этом разделе описываются высокоуровневые asyncio-API 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 subprocess асинхронны, а asyncio предоставляет множество инструментов для работы с такими функциями, легко выполнять и отслеживать несколько подпроцессов параллельно. Действительно, легко изменить приведенный выше пример, чтобы запустить несколько команд одновременно:

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

asyncio.run(main())

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

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

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

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

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

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

См. документацию loop.subprocess_exec() для других параметров.

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

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

Выполнить командную строку cmd.

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

Возвращает экземпляр 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.

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

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

asyncio.subprocess.STDOUT

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

asyncio.subprocess.DEVNULL

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

END_OF_DOCUMENT_MARKER

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

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

class asyncio.subprocess.Process

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

Этот класс разработан с API, аналогичным классу subprocess.Popen, но существуют некоторые заметные отличия:

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

Этот класс не потокобезопасен.

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

coroutine wait()

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

Устанавливает и возвращает атрибут returncode.

Примечание

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

coroutine communicate(input=None)

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

  1. отправка данных в stdin (если input не None);
  2. закрытие stdin;
  3. чтение данных из stdout и stderr, пока не будет достигнут конец файла;
  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).

Дочерние процессы и потоки

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

В 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