asyncio-subprocess.md
1> **Источник:** https://python-all.ru/3.15/library/asyncio-subprocess.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# Подпроцессы89**Исходный код:** [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)1011---1213В этом разделе описываются высокоуровневые async/await asyncio API для создания и управления подпроцессами.1415Вот пример того, как asyncio может выполнить команду оболочки и получить её результат:1617```python18import asyncio1920async def run(cmd):21 proc = await asyncio.create_subprocess_shell(22 cmd,23 stdout=asyncio.subprocess.PIPE,24 stderr=asyncio.subprocess.PIPE)2526 stdout, stderr = await proc.communicate()2728 print(f'[{cmd!r} exited with {proc.returncode}]')29 if stdout:30 print(f'[stdout]\n{stdout.decode()}')31 if stderr:32 print(f'[stderr]\n{stderr.decode()}')3334asyncio.run(run('ls /zzz'))35```3637выведет:3839```python40['ls /zzz' exited with 1]41[stderr]42ls: /zzz: No such file or directory43```4445Поскольку все функции asyncio для работы с подпроцессами являются асинхронными, и asyncio предоставляет множество инструментов для работы с такими функциями, легко выполнять и контролировать несколько подпроцессов параллельно. Действительно, тривиально изменить пример выше, чтобы запустить несколько команд одновременно:4647```python48async def main():49 await asyncio.gather(50 run('ls /zzz'),51 run('sleep 1; echo "hello"'))5253asyncio.run(main())54```5556См. также подраздел [Примеры](https://python-all.ru/3.15/library/asyncio-subprocess.html#examples).5758## Создание подпроцессов5960#### `async asyncio.create_subprocess_exec(program, *args, stdin=None, stdout=None, stderr=None, limit=None, **kwds)`6162Создание подпроцесса.6364Аргумент *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*).6566Возвращает экземпляр [`Process`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.subprocess.Process).6768См. документацию [`loop.subprocess_exec()`](https://python-all.ru/3.15/library/asyncio-eventloop.html#asyncio.loop.subprocess_exec) для других параметров.6970Если объект процесса собирается сборщиком мусора во время выполнения процесса, дочерний процесс будет убит.7172Изменено в версии 3.10: Удалён параметр *loop*.7374#### `async asyncio.create_subprocess_shell(cmd, stdin=None, stdout=None, stderr=None, limit=None, **kwds)`7576Выполняет команду оболочки *cmd*.7778Аргумент *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*).7980Возвращает экземпляр [`Process`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.subprocess.Process).8182См. документацию [`loop.subprocess_shell()`](https://python-all.ru/3.15/library/asyncio-eventloop.html#asyncio.loop.subprocess_shell) для других параметров.8384Если объект процесса собирается сборщиком мусора во время выполнения процесса, дочерний процесс будет убит.8586> **Важно**87>88> На приложении лежит ответственность за то, чтобы все пробельные и специальные символы были экранированы должным образом для предотвращения уязвимостей [внедрения команд оболочки](https://python-all.ru/3.15/library/asyncio-subprocess.html). Функция [`shlex.quote()`](https://python-all.ru/3.15/library/shlex.html#shlex.quote) может использоваться для правильного экранирования пробельных и специальных символов оболочки в строках, которые будут использоваться для построения команд оболочки.8990Изменено в версии 3.10: Удалён параметр *loop*.9192> **Примечание**93>94> Подпроцессы доступны в 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).9596> **См. также**97>98> 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).99100## Константы101102#### `asyncio.subprocess.PIPE`103104Может быть передан в параметры *stdin*, *stdout* или *stderr*.105106Если *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).107108Если *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).109110#### `asyncio.subprocess.STDOUT`111112Специальное значение, которое можно использовать в качестве аргумента *stderr*, указывающее, что стандартный поток ошибок должен быть перенаправлен в стандартный вывод.113114#### `asyncio.subprocess.DEVNULL`115116Специальное значение, которое можно использовать в качестве аргумента *stdin*, *stdout* или *stderr* для функций создания процессов. Оно указывает, что для соответствующего потока подпроцесса будет использован специальный файл [`os.devnull`](https://python-all.ru/3.15/library/os.html#os.devnull).117118## Взаимодействие с подпроцессами119120Функции [`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* – это высокоуровневая обёртка, которая позволяет взаимодействовать с подпроцессами и отслеживать их завершение.121122#### `class asyncio.subprocess.Process`123124Объект, который оборачивает процессы ОС, созданные функциями [`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).125126Этот класс спроектирован с API, похожим на класс [`subprocess.Popen`](https://python-all.ru/3.15/library/subprocess.html#subprocess.Popen), но есть некоторые существенные отличия:127128- в отличие от Popen, экземпляры Process не имеют эквивалента методу [`poll()`](https://python-all.ru/3.15/library/subprocess.html#subprocess.Popen.poll);129- методы [`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);130- метод [`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) реализован как блокирующий цикл ожидания;131- параметр *universal\_newlines* не поддерживается.132133This class is [не является потокобезопасным](https://python-all.ru/3.15/library/asyncio-dev.html#asyncio-multithreading).134135См. также раздел [Подпроцессы и потоки](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio-subprocess-threads) .136137#### `async wait()`138139Ожидает завершения дочернего процесса.140141Устанавливает и возвращает атрибут [`returncode`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.subprocess.Process.returncode).142143> **Примечание**144>145> Этот метод может привести к взаимоблокировке при использовании `stdout=PIPE` или `stderr=PIPE`, если дочерний процесс генерирует настолько много вывода, что он блокируется в ожидании, пока буфер системного канала (pipe) примет больше данных. Во избежание этой ситуации используйте метод [`communicate()`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.subprocess.Process.communicate) при работе с каналами.146147#### `async communicate(input=None)`148149Взаимодействие с процессом:1501511. отправляет данные в *stdin* (если *input* не равен `None`);1522. закрывает *stdin*;1533. читает данные из *stdout* и *stderr* до достижения конца файла (EOF);1544. ожидает завершения процесса.155156Необязательный аргумент *input* – это данные (объект [`bytes`](https://python-all.ru/3.15/library/stdtypes.html#bytes)), которые будут отправлены дочернему процессу.157158Возвращает кортеж `(stdout_data, stderr_data)`.159160Если возникает исключение [`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*.161162Если требуется отправить данные в *stdin* процесса, процесс должен быть создан с `stdin=PIPE`. Аналогично, чтобы получить в результирующем кортеже что-то, отличное от `None`, процесс должен быть создан с аргументами `stdout=PIPE` и/или `stderr=PIPE`.163164Обратите внимание, что прочитанные данные буферизуются в памяти, поэтому не используйте этот метод, если размер данных велик или неограничен.165166Изменено в версии 3.12: *stdin* также закрывается при `input=None`.167168#### `send_signal(signal)`169170Отправляет сигнал *signal* дочернему процессу.171172> **Примечание**173>174> В 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`.175176#### `terminate()`177178Останавливает дочерний процесс.179180В системах POSIX этот метод отправляет [`SIGTERM`](https://python-all.ru/3.15/library/signal.html#signal.SIGTERM) дочернему процессу.181182В Windows для остановки дочернего процесса вызывается функция Win32 API `TerminateProcess()`.183184#### `kill()`185186Завершает дочерний процесс.187188В системах POSIX этот метод отправляет [`SIGKILL`](https://python-all.ru/3.15/library/signal.html#signal.SIGKILL) дочернему процессу.189190В Windows этот метод является псевдонимом для [`terminate()`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.subprocess.Process.terminate).191192#### `stdin`193194Поток стандартного ввода ([`StreamWriter`](https://python-all.ru/3.15/library/asyncio-stream.html#asyncio.StreamWriter)) или `None`, если процесс был создан с `stdin=None`.195196#### `stdout`197198Поток стандартного вывода ([`StreamReader`](https://python-all.ru/3.15/library/asyncio-stream.html#asyncio.StreamReader)) или `None`, если процесс был создан с `stdout=None`.199200#### `stderr`201202Поток стандартного вывода ошибок ([`StreamReader`](https://python-all.ru/3.15/library/asyncio-stream.html#asyncio.StreamReader)) или `None`, если процесс был создан с `stderr=None`.203204> **Предупреждение**205>206> Используйте метод [`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). Это позволяет избежать взаимоблокировок, возникающих из-за приостановки чтения или записи потоков и блокировки дочернего процесса.207208#### `pid`209210Идентификатор процесса (PID).211212Обратите внимание: для процессов, созданных функцией [`create_subprocess_shell()`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.create_subprocess_shell), этот атрибут содержит PID запущенной оболочки.213214#### `returncode`215216Код возврата процесса при его завершении.217218Значение `None` указывает на то, что процесс ещё не завершён.219220Для процессов, созданных с [`create_subprocess_exec()`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.create_subprocess_exec), отрицательное значение `-N` означает, что дочерний процесс был завершён сигналом `N` (только POSIX).221222Для процессов, созданных с [`create_subprocess_shell()`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.create_subprocess_shell), код возврата отражает статус выхода самой оболочки (например, `/bin/sh`), который может отображать сигналы на такие коды, как `128+N`. Подробнее см. в документации оболочки (например, раздел Exit Status руководства Bash).223224### Подпроцессы и потоки225226Стандартный цикл событий asyncio поддерживает запуск подпроцессов из разных потоков по умолчанию.227228В 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) не поддерживает подпроцессы.229230Обратите внимание: альтернативные реализации цикла событий могут иметь собственные ограничения; обратитесь к их документации.231232> **См. также**233>234> Раздел [Конкурентность и многопоточность в asyncio](https://python-all.ru/3.15/library/asyncio-dev.html#asyncio-multithreading).235236### Примеры237238Пример использования класса [`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) для чтения из его стандартного вывода.239240Подпроцесс создаётся функцией [`create_subprocess_exec()`](https://python-all.ru/3.15/library/asyncio-subprocess.html#asyncio.create_subprocess_exec):241242```python243import asyncio244import sys245246async def get_date():247 code = 'import datetime as dt; print(dt.datetime.now())'248249 # Создать подпроцесс; перенаправить стандартный вывод250 # в канал.251 proc = await asyncio.create_subprocess_exec(252 sys.executable, '-c', code,253 stdout=asyncio.subprocess.PIPE)254255 # Прочитать одну строку вывода.256 data = await proc.stdout.readline()257 line = data.decode('ascii').rstrip()258259 # Дождаться завершения подпроцесса.260 await proc.wait()261 return line262263date = asyncio.run(get_date())264print(f"Current date: {date}")265```266267См. также [тот же пример](https://python-all.ru/3.15/library/asyncio-protocol.html#asyncio-example-subprocess-proto), написанный с использованием низкоуровневых API.268