> **Источник:** https://python-all.ru/3.15/library/asyncio-subprocess.html
>
> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.

---

# Подпроцессы

**Исходный код:** [Lib/asyncio/subprocess.py](https://python-all.ru/src/3.15/Lib/asyncio/subprocess.py), [Lib/asyncio/base\_subprocess.py](https://python-all.ru/src/3.15/Lib/asyncio/base_subprocess.py)

---

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

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

```python
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'))
```

выведет:

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

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

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

asyncio.run(main())
```

См. также подраздел [Примеры](https://python-all.ru/3.15/library/asyncio-subprocess.html#examples).

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

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

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

Аргумент *limit* устанавливает ограничение буфера для обёрток [`StreamReader`](https://python-all.ru/3.15/library/asyncio-stream.html#asyncio.StreamReader) для [`stdout`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.subprocess.Process.stdout) и [`stderr`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.subprocess.Process.stderr) (если [`subprocess.PIPE`](https://python-all.ru/3.15/library/subprocess.html#subprocess.PIPE) передаётся в аргументы *stdout* и *stderr*).

Возвращает экземпляр [`Process`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.subprocess.Process).

См. документацию [`loop.subprocess_exec()`](https://python-all.ru/3.15/library/asyncio-eventloop.html#asyncio.loop.subprocess_exec) для других параметров.

Если объект процесса собирается сборщиком мусора во время выполнения процесса, дочерний процесс будет убит.

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

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

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

Аргумент *limit* устанавливает ограничение буфера для обёрток [`StreamReader`](https://python-all.ru/3.15/library/asyncio-stream.html#asyncio.StreamReader) для [`stdout`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.subprocess.Process.stdout) и [`stderr`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.subprocess.Process.stderr) (если [`subprocess.PIPE`](https://python-all.ru/3.15/library/subprocess.html#subprocess.PIPE) передаётся в аргументы *stdout* и *stderr*).

Возвращает экземпляр [`Process`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.subprocess.Process).

См. документацию [`loop.subprocess_shell()`](https://python-all.ru/3.15/library/asyncio-eventloop.html#asyncio.loop.subprocess_shell) для других параметров.

Если объект процесса собирается сборщиком мусора во время выполнения процесса, дочерний процесс будет убит.

> **Важно**
>
> На приложении лежит ответственность за то, чтобы все пробельные и специальные символы были экранированы должным образом для предотвращения уязвимостей [внедрения команд оболочки](https://python-all.ru/3.15/library/asyncio-subprocess.html). Функция [`shlex.quote()`](https://python-all.ru/3.15/library/shlex.html#shlex.quote) может использоваться для правильного экранирования пробельных и специальных символов оболочки в строках, которые будут использоваться для построения команд оболочки.

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

> **Примечание**
>
> Подпроцессы доступны в Windows, если используется [`ProactorEventLoop`](https://python-all.ru/3.15/library/asyncio-eventloop.html#asyncio.ProactorEventLoop). Подробнее см. [Поддержка подпроцессов в Windows](https://python-all.ru/3.15/library/asyncio-platforms.html#asyncio-windows-subprocess).

> **См. также**
>
> asyncio также предоставляет следующие *низкоуровневые* API для работы с подпроцессами: [`loop.subprocess_exec()`](https://python-all.ru/3.15/library/asyncio-eventloop.html#asyncio.loop.subprocess_exec), [`loop.subprocess_shell()`](https://python-all.ru/3.15/library/asyncio-eventloop.html#asyncio.loop.subprocess_shell), [`loop.connect_read_pipe()`](https://python-all.ru/3.15/library/asyncio-eventloop.html#asyncio.loop.connect_read_pipe), [`loop.connect_write_pipe()`](https://python-all.ru/3.15/library/asyncio-eventloop.html#asyncio.loop.connect_write_pipe), а также [Транспорты подпроцессов](https://python-all.ru/3.15/library/asyncio-protocol.html#asyncio-subprocess-transports) и [Протоколы подпроцессов](https://python-all.ru/3.15/library/asyncio-protocol.html#asyncio-subprocess-protocols).

## Константы

#### `asyncio.subprocess.PIPE`

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

Если *PIPE* передаётся в аргумент *stdin*, то атрибут [`Process.stdin`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.subprocess.Process.stdin) будет указывать на экземпляр [`StreamWriter`](https://python-all.ru/3.15/library/asyncio-stream.html#asyncio.StreamWriter).

Если *PIPE* передаётся в аргументы *stdout* или *stderr*, то атрибуты [`Process.stdout`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.subprocess.Process.stdout) и [`Process.stderr`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.subprocess.Process.stderr) будут указывать на экземпляры [`StreamReader`](https://python-all.ru/3.15/library/asyncio-stream.html#asyncio.StreamReader).

#### `asyncio.subprocess.STDOUT`

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

#### `asyncio.subprocess.DEVNULL`

Специальное значение, которое можно использовать в качестве аргумента *stdin*, *stdout* или *stderr* для функций создания процессов. Оно указывает, что для соответствующего потока подпроцесса будет использован специальный файл [`os.devnull`](https://python-all.ru/3.15/library/os.html#os.devnull).

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

Функции [`create_subprocess_exec()`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.create_subprocess_exec) и [`create_subprocess_shell()`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.create_subprocess_shell) возвращают экземпляры класса *Process*. *Process* – это высокоуровневая обёртка, которая позволяет взаимодействовать с подпроцессами и отслеживать их завершение.

#### `class asyncio.subprocess.Process`

Объект, который оборачивает процессы ОС, созданные функциями [`create_subprocess_exec()`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.create_subprocess_exec) и [`create_subprocess_shell()`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.create_subprocess_shell).

Этот класс спроектирован с API, похожим на класс [`subprocess.Popen`](https://python-all.ru/3.15/library/subprocess.html#subprocess.Popen), но есть некоторые существенные отличия:

- в отличие от Popen, экземпляры Process не имеют эквивалента методу [`poll()`](https://python-all.ru/3.15/library/subprocess.html#subprocess.Popen.poll);
- методы [`communicate()`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.subprocess.Process.communicate) и [`wait()`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.subprocess.Process.wait) не имеют параметра *timeout*: используйте функцию [`wait_for()`](https://python-all.ru/3.15/library/asyncio-task.html#asyncio.wait_for);
- метод [`Process.wait()`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.subprocess.Process.wait) является асинхронным, тогда как метод [`subprocess.Popen.wait()`](https://python-all.ru/3.15/library/subprocess.html#subprocess.Popen.wait) реализован как блокирующий цикл ожидания;
- параметр *universal\_newlines* не поддерживается.

This class is [не является потокобезопасным](https://python-all.ru/3.15/library/asyncio-dev.html#asyncio-multithreading).

См. также раздел [Подпроцессы и потоки](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio-subprocess-threads) .

#### `async wait()`

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

Устанавливает и возвращает атрибут [`returncode`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.subprocess.Process.returncode).

> **Примечание**
>
> Этот метод может привести к взаимоблокировке при использовании `stdout=PIPE` или `stderr=PIPE`, если дочерний процесс генерирует настолько много вывода, что он блокируется в ожидании, пока буфер системного канала (pipe) примет больше данных. Во избежание этой ситуации используйте метод [`communicate()`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.subprocess.Process.communicate) при работе с каналами.

#### `async communicate(input=None)`

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

1. отправляет данные в *stdin* (если *input* не равен `None`);
2. закрывает *stdin*;
3. читает данные из *stdout* и *stderr* до достижения конца файла (EOF);
4. ожидает завершения процесса.

Необязательный аргумент *input* – это данные (объект [`bytes`](https://python-all.ru/3.15/library/stdtypes.html#bytes)), которые будут отправлены дочернему процессу.

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

Если возникает исключение [`BrokenPipeError`](https://python-all.ru/3.15/library/exceptions.html#BrokenPipeError) или [`ConnectionResetError`](https://python-all.ru/3.15/library/exceptions.html#ConnectionResetError) при записи *input* в *stdin*, это исключение игнорируется. Такая ситуация возникает, когда процесс завершается до того, как все данные будут записаны в *stdin*.

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

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

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

#### `send_signal(signal)`

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

> **Примечание**
>
> В Windows [`SIGTERM`](https://python-all.ru/3.15/library/signal.html#signal.SIGTERM) является псевдонимом для [`terminate()`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.subprocess.Process.terminate). `CTRL_C_EVENT` и `CTRL_BREAK_EVENT` могут быть отправлены процессам, запущенным с параметром *creationflags*, который содержит `CREATE_NEW_PROCESS_GROUP`.

#### `terminate()`

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

В системах POSIX этот метод отправляет [`SIGTERM`](https://python-all.ru/3.15/library/signal.html#signal.SIGTERM) дочернему процессу.

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

#### `kill()`

Завершает дочерний процесс.

В системах POSIX этот метод отправляет [`SIGKILL`](https://python-all.ru/3.15/library/signal.html#signal.SIGKILL) дочернему процессу.

В Windows этот метод является псевдонимом для [`terminate()`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.subprocess.Process.terminate).

#### `stdin`

Поток стандартного ввода ([`StreamWriter`](https://python-all.ru/3.15/library/asyncio-stream.html#asyncio.StreamWriter)) или `None`, если процесс был создан с `stdin=None`.

#### `stdout`

Поток стандартного вывода ([`StreamReader`](https://python-all.ru/3.15/library/asyncio-stream.html#asyncio.StreamReader)) или `None`, если процесс был создан с `stdout=None`.

#### `stderr`

Поток стандартного вывода ошибок ([`StreamReader`](https://python-all.ru/3.15/library/asyncio-stream.html#asyncio.StreamReader)) или `None`, если процесс был создан с `stderr=None`.

> **Предупреждение**
>
> Используйте метод [`communicate()`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.subprocess.Process.communicate) вместо [`process.stdin.write()`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.subprocess.Process.stdin), [`await process.stdout.read()`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.subprocess.Process.stdout) или [`await process.stderr.read()`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.subprocess.Process.stderr). Это позволяет избежать взаимоблокировок, возникающих из-за приостановки чтения или записи потоков и блокировки дочернего процесса.

#### `pid`

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

Обратите внимание: для процессов, созданных функцией [`create_subprocess_shell()`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.create_subprocess_shell), этот атрибут содержит PID запущенной оболочки.

#### `returncode`

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

Значение `None` указывает на то, что процесс ещё не завершён.

Для процессов, созданных с [`create_subprocess_exec()`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.create_subprocess_exec), отрицательное значение `-N` означает, что дочерний процесс был завершён сигналом `N` (только POSIX).

Для процессов, созданных с [`create_subprocess_shell()`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.create_subprocess_shell), код возврата отражает статус выхода самой оболочки (например, `/bin/sh`), который может отображать сигналы на такие коды, как `128+N`. Подробнее см. в документации оболочки (например, раздел Exit Status руководства Bash).

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

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

В Windows подпроцессы поддерживаются только [`ProactorEventLoop`](https://python-all.ru/3.15/library/asyncio-eventloop.html#asyncio.ProactorEventLoop) (по умолчанию), [`SelectorEventLoop`](https://python-all.ru/3.15/library/asyncio-eventloop.html#asyncio.SelectorEventLoop) не поддерживает подпроцессы.

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

> **См. также**
>
> Раздел [Конкурентность и многопоточность в asyncio](https://python-all.ru/3.15/library/asyncio-dev.html#asyncio-multithreading).

### Примеры

Пример использования класса [`Process`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.subprocess.Process) для управления подпроцессом и класса [`StreamReader`](https://python-all.ru/3.15/library/asyncio-stream.html#asyncio.StreamReader) для чтения из его стандартного вывода.

Подпроцесс создаётся функцией [`create_subprocess_exec()`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.create_subprocess_exec):

```python
import asyncio
import sys

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

    # Создать подпроцесс; перенаправить стандартный вывод
    # в канал.
    proc = await asyncio.create_subprocess_exec(
        sys.executable, '-c', code,
        stdout=asyncio.subprocess.PIPE)

    # Прочитать одну строку вывода.
    data = await proc.stdout.readline()
    line = data.decode('ascii').rstrip()

    # Дождаться завершения подпроцесса.
    await proc.wait()
    return line

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

См. также [тот же пример](https://python-all.ru/3.15/library/asyncio-protocol.html#asyncio-example-subprocess-proto), написанный с использованием низкоуровневых API.
