asyncio-subprocess.md
1> **Источник:** https://python-all.ru/3.6/library/asyncio-subprocess.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 18.5.6. Подпроцесс89**Исходный код:** [Lib/asyncio/subprocess.py](https://python-all.ru/src/3.6/Lib/asyncio/subprocess.py)1011## 18.5.6.1. Цикл событий Windows1213В Windows цикл событий по умолчанию – [`SelectorEventLoop`](https://python-all.ru/3.6/library/asyncio-eventloops.html#asyncio.SelectorEventLoop), который не поддерживает подпроцессы. Вместо него следует использовать [`ProactorEventLoop`](https://python-all.ru/3.6/library/asyncio-eventloops.html#asyncio.ProactorEventLoop). Пример использования в Windows:1415```python16import asyncio, sys1718if sys.platform == 'win32':19 loop = asyncio.ProactorEventLoop()20 asyncio.set_event_loop(loop)21```2223> **См. также**24>25> [Доступные циклы событий](https://python-all.ru/3.6/library/asyncio-eventloops.html#asyncio-event-loops) и [Поддержка платформ](https://python-all.ru/3.6/library/asyncio-eventloops.html#asyncio-platform-support).2627## 18.5.6.2. Создание подпроцесса: высокоуровневый API с использованием процесса2829#### `coroutine asyncio.create_subprocess_exec(*args, stdin=None, stdout=None, stderr=None, loop=None, limit=None, **kwds)`3031Создание подпроцесса.3233Параметр *limit* устанавливает лимит буфера, передаваемый в [`StreamReader`](https://python-all.ru/3.6/library/asyncio-stream.html#asyncio.StreamReader). Дополнительные параметры см. в [`AbstractEventLoop.subprocess_exec()`](https://python-all.ru/3.6/library/asyncio-subprocess.html#asyncio.AbstractEventLoop.subprocess_exec).3435Возвращает экземпляр [`Process`](https://python-all.ru/3.6/library/asyncio-subprocess.html#asyncio.asyncio.subprocess.Process).3637Эта функция – [корутина](https://python-all.ru/3.6/library/asyncio-task.html#coroutine).3839#### `coroutine asyncio.create_subprocess_shell(cmd, stdin=None, stdout=None, stderr=None, loop=None, limit=None, **kwds)`4041Выполняет команду оболочки *cmd*.4243Параметр *limit* устанавливает лимит буфера, передаваемый в [`StreamReader`](https://python-all.ru/3.6/library/asyncio-stream.html#asyncio.StreamReader). Дополнительные параметры см. в [`AbstractEventLoop.subprocess_shell()`](https://python-all.ru/3.6/library/asyncio-subprocess.html#asyncio.AbstractEventLoop.subprocess_shell).4445Возвращает экземпляр [`Process`](https://python-all.ru/3.6/library/asyncio-subprocess.html#asyncio.asyncio.subprocess.Process).4647Приложение должно гарантировать, что все пробельные символы и метасимволы правильно экранированы, чтобы избежать уязвимостей типа [внедрение команд оболочки](https://python-all.ru/3.6/library/asyncio-subprocess.html). Функция [`shlex.quote()`](https://python-all.ru/3.6/library/shlex.html#shlex.quote) позволяет правильно экранировать пробельные символы и метасимволы оболочки в строках, которые будут использоваться для построения команд оболочки.4849Эта функция – [корутина](https://python-all.ru/3.6/library/asyncio-task.html#coroutine).5051Используйте методы [`AbstractEventLoop.connect_read_pipe()`](https://python-all.ru/3.6/library/asyncio-eventloop.html#asyncio.AbstractEventLoop.connect_read_pipe) и [`AbstractEventLoop.connect_write_pipe()`](https://python-all.ru/3.6/library/asyncio-eventloop.html#asyncio.AbstractEventLoop.connect_write_pipe) для подключения каналов.5253## 18.5.6.3. Создание подпроцесса: низкоуровневый API с использованием subprocess.Popen5455Асинхронный запуск подпроцессов с помощью модуля [`subprocess`](https://python-all.ru/3.6/library/subprocess.html#module-subprocess).5657#### `coroutine AbstractEventLoop.subprocess_exec(protocol_factory, *args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)`5859Создание подпроцесса из одного или нескольких строковых аргументов (строки символов или байтовые строки, закодированные в [кодировку файловой системы](https://python-all.ru/3.6/library/os.html#filesystem-encoding)), где первая строка определяет выполняемую программу, а остальные строки – её аргументы. (Таким образом, вместе строковые аргументы образуют значение `sys.argv` программы, если предположить, что это скрипт Python.) Это похоже на класс [`subprocess.Popen`](https://python-all.ru/3.6/library/subprocess.html#subprocess.Popen) из стандартной библиотеки, вызываемый с shell=False и списком строк, передаваемым в качестве первого аргумента; однако [`Popen`](https://python-all.ru/3.6/library/subprocess.html#subprocess.Popen) принимает один аргумент – список строк, а [`subprocess_exec()`](https://python-all.ru/3.6/library/asyncio-subprocess.html#asyncio.AbstractEventLoop.subprocess_exec) принимает несколько строковых аргументов.6061Параметр *protocol\_factory* должен создавать экземпляр подкласса класса [`asyncio.SubprocessProtocol`](https://python-all.ru/3.6/library/asyncio-protocol.html#asyncio.SubprocessProtocol).6263Другие параметры:6465- *stdin*: либо файлоподобный объект, представляющий канал, который будет подключён к стандартному потоку ввода подпроцесса с помощью [`connect_write_pipe()`](https://python-all.ru/3.6/library/asyncio-eventloop.html#asyncio.AbstractEventLoop.connect_write_pipe), либо константа [`subprocess.PIPE`](https://python-all.ru/3.6/library/subprocess.html#subprocess.PIPE) (по умолчанию). По умолчанию создаётся и подключается новый канал.66- *stdout*: либо файлоподобный объект, представляющий канал, который будет подключён к стандартному потоку вывода подпроцесса с помощью [`connect_read_pipe()`](https://python-all.ru/3.6/library/asyncio-eventloop.html#asyncio.AbstractEventLoop.connect_read_pipe), либо константа [`subprocess.PIPE`](https://python-all.ru/3.6/library/subprocess.html#subprocess.PIPE) (по умолчанию). По умолчанию создаётся и подключается новый канал.67- *stderr*: либо файлоподобный объект, представляющий канал, который будет подключён к стандартному потоку ошибок подпроцесса с помощью [`connect_read_pipe()`](https://python-all.ru/3.6/library/asyncio-eventloop.html#asyncio.AbstractEventLoop.connect_read_pipe), либо одна из констант [`subprocess.PIPE`](https://python-all.ru/3.6/library/subprocess.html#subprocess.PIPE) (по умолчанию) или [`subprocess.STDOUT`](https://python-all.ru/3.6/library/subprocess.html#subprocess.STDOUT). По умолчанию создаётся и подключается новый канал. Если указано [`subprocess.STDOUT`](https://python-all.ru/3.6/library/subprocess.html#subprocess.STDOUT), стандартный поток ошибок подпроцесса будет подключён к тому же каналу, что и стандартный поток вывода.68- Все остальные именованные аргументы передаются в [`subprocess.Popen`](https://python-all.ru/3.6/library/subprocess.html#subprocess.Popen) без интерпретации, за исключением *bufsize*, *universal\_newlines* и *shell*, которые не следует указывать вовсе.6970Возвращает пару `(transport, protocol)`, где *транспорт* – экземпляр [`BaseSubprocessTransport`](https://python-all.ru/3.6/library/asyncio-protocol.html#asyncio.BaseSubprocessTransport).7172Этот метод – [корутина](https://python-all.ru/3.6/library/asyncio-task.html#coroutine).7374Параметры см. в конструкторе класса [`subprocess.Popen`](https://python-all.ru/3.6/library/subprocess.html#subprocess.Popen).7576#### `coroutine AbstractEventLoop.subprocess_shell(protocol_factory, cmd, *, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)`7778Создание подпроцесса из *cmd* – строки символов или байтовой строки, закодированной в [кодировку файловой системы](https://python-all.ru/3.6/library/os.html#filesystem-encoding), с использованием синтаксиса оболочки платформы. Это похоже на класс [`subprocess.Popen`](https://python-all.ru/3.6/library/subprocess.html#subprocess.Popen) из стандартной библиотеки, вызываемый с `shell=True`.7980Параметр *protocol\_factory* должен создавать экземпляр подкласса класса [`asyncio.SubprocessProtocol`](https://python-all.ru/3.6/library/asyncio-protocol.html#asyncio.SubprocessProtocol).8182Подробнее об остальных аргументах см. в [`subprocess_exec()`](https://python-all.ru/3.6/library/asyncio-subprocess.html#asyncio.AbstractEventLoop.subprocess_exec).8384Возвращает пару `(transport, protocol)`, где *транспорт* – экземпляр [`BaseSubprocessTransport`](https://python-all.ru/3.6/library/asyncio-protocol.html#asyncio.BaseSubprocessTransport).8586Приложение должно гарантировать, что все пробельные символы и метасимволы правильно экранированы, чтобы избежать уязвимостей типа [внедрение команд оболочки](https://python-all.ru/3.6/library/asyncio-subprocess.html). Функция [`shlex.quote()`](https://python-all.ru/3.6/library/shlex.html#shlex.quote) позволяет правильно экранировать пробельные символы и метасимволы оболочки в строках, которые будут использоваться для построения команд оболочки.8788Этот метод – [корутина](https://python-all.ru/3.6/library/asyncio-task.html#coroutine).8990> **См. также**91>92> Методы [`AbstractEventLoop.connect_read_pipe()`](https://python-all.ru/3.6/library/asyncio-eventloop.html#asyncio.AbstractEventLoop.connect_read_pipe) и [`AbstractEventLoop.connect_write_pipe()`](https://python-all.ru/3.6/library/asyncio-eventloop.html#asyncio.AbstractEventLoop.connect_write_pipe).9394## 18.5.6.4. Константы9596#### `asyncio.subprocess.PIPE`9798Специальное значение, которое можно использовать в качестве аргумента *stdin*, *stdout* или *stderr*\\nдля [`create_subprocess_shell()`](https://python-all.ru/3.6/library/asyncio-subprocess.html#asyncio.create_subprocess_shell) и [`create_subprocess_exec()`](https://python-all.ru/3.6/library/asyncio-subprocess.html#asyncio.create_subprocess_exec), и\\nуказывающее, что должен быть открыт канал к стандартному потоку.99100#### `asyncio.subprocess.STDOUT`101102Специальное значение, которое можно использовать в качестве аргумента *stderr* для\\n[`create_subprocess_shell()`](https://python-all.ru/3.6/library/asyncio-subprocess.html#asyncio.create_subprocess_shell) и [`create_subprocess_exec()`](https://python-all.ru/3.6/library/asyncio-subprocess.html#asyncio.create_subprocess_exec), и\\nуказывающее, что стандартный поток ошибок должен направляться в тот же дескриптор, что и стандартный вывод.103104#### `asyncio.subprocess.DEVNULL`105106Специальное значение, которое можно использовать в качестве аргумента *stdin*, *stdout* или *stderr*\\nдля [`create_subprocess_shell()`](https://python-all.ru/3.6/library/asyncio-subprocess.html#asyncio.create_subprocess_shell) и [`create_subprocess_exec()`](https://python-all.ru/3.6/library/asyncio-subprocess.html#asyncio.create_subprocess_exec), и\\nуказывающее, что будет использоваться специальный файл [`os.devnull`](https://python-all.ru/3.6/library/os.html#os.devnull).107108## 18.5.6.5. Процесс109110#### `class asyncio.subprocess.Process`111112Подпроцесс, созданный функцией [`create_subprocess_exec()`](https://python-all.ru/3.6/library/asyncio-subprocess.html#asyncio.create_subprocess_exec) или\\n[`create_subprocess_shell()`](https://python-all.ru/3.6/library/asyncio-subprocess.html#asyncio.create_subprocess_shell).113114API класса [`Process`](https://python-all.ru/3.6/library/asyncio-subprocess.html#asyncio.asyncio.subprocess.Process) разработан так, чтобы быть близким к API класса [`subprocess.Popen`](https://python-all.ru/3.6/library/subprocess.html#subprocess.Popen), но есть некоторые различия:115116- Нет явного метода [`poll()`](https://python-all.ru/3.6/library/subprocess.html#subprocess.Popen.poll)117- Методы [`communicate()`](https://python-all.ru/3.6/library/subprocess.html#subprocess.Popen.communicate) и\\n[`wait()`](https://python-all.ru/3.6/library/subprocess.html#subprocess.Popen.wait) не принимают параметр *timeout*:\\nиспользуйте функцию [`wait_for()`](https://python-all.ru/3.6/library/asyncio-task.html#asyncio.wait_for)118- Параметр *universal\_newlines* не поддерживается (поддерживаются только строки байтов)119- Метод [`wait()`](https://python-all.ru/3.6/library/asyncio-subprocess.html#asyncio.asyncio.subprocess.Process.wait) класса\\n[`Process`](https://python-all.ru/3.6/library/asyncio-subprocess.html#asyncio.asyncio.subprocess.Process) является асинхронным, тогда как\\nметод [`wait()`](https://python-all.ru/3.6/library/subprocess.html#subprocess.Popen.wait) класса [`Popen`](https://python-all.ru/3.6/library/subprocess.html#subprocess.Popen)\\nреализован как активный цикл ожидания.120121Этот класс [не потокобезопасен](https://python-all.ru/3.6/library/asyncio-dev.html#asyncio-multithreading). См. также раздел\\n[Подпроцессы и потоки](https://python-all.ru/3.6/library/asyncio-subprocess.html#asyncio-subprocess-threads).122123#### `coroutine wait()`124125Ожидать завершения дочернего процесса. Установить и вернуть атрибут [`returncode`](https://python-all.ru/3.6/library/asyncio-subprocess.html#asyncio.asyncio.subprocess.Process.returncode).126127Этот метод является [корутиной](https://python-all.ru/3.6/library/asyncio-task.html#coroutine).128129> **Примечание**130>131> Это приведёт к взаимоблокировке при использовании `stdout=PIPE` или `stderr=PIPE`, если\\nдочерний процесс генерирует достаточно выходных данных в канал, так что он\\nблокируется в ожидании, когда буфер канала ОС сможет принять больше данных. Используйте\\nметод [`communicate()`](https://python-all.ru/3.6/library/asyncio-subprocess.html#asyncio.asyncio.subprocess.Process.communicate) при работе с каналами, чтобы избежать этого.132133#### `coroutine communicate(input=None)`134135Взаимодействие с процессом: отправить данные в стандартный ввод. Читать данные из стандартного вывода и стандартного вывода ошибок до достижения конца файла. Ожидать завершения процесса. Необязательный аргумент *input* должен содержать данные для отправки дочернему процессу, или `None`, если данные не нужно отправлять. Тип *input* должен быть байтовым.136137[`communicate()`](https://python-all.ru/3.6/library/asyncio-subprocess.html#asyncio.asyncio.subprocess.Process.communicate) возвращает кортеж `(stdout_data, stderr_data)`.138139Если исключение [`BrokenPipeError`](https://python-all.ru/3.6/library/exceptions.html#BrokenPipeError) или [`ConnectionResetError`](https://python-all.ru/3.6/library/exceptions.html#ConnectionResetError) возникает\\nпри записи *input* в stdin, это исключение игнорируется. Оно\\nвозникает, когда процесс завершается до того, как все данные будут записаны в stdin.140141Обратите внимание: если требуется отправить данные в stdin процесса, необходимо создать объект процесса с `stdin=PIPE`. Аналогично, чтобы получить в результирующем кортеже что-то кроме `None`, нужно также указать `stdout=PIPE` и/или `stderr=PIPE`.142143Этот метод является [корутиной](https://python-all.ru/3.6/library/asyncio-task.html#coroutine).144145> **Примечание**146>147> Прочитанные данные буферизируются в памяти, поэтому не следует использовать этот метод, если\\nразмер данных велик или неограничен.148149Изменено в версии 3.4.2: Метод теперь игнорирует [`BrokenPipeError`](https://python-all.ru/3.6/library/exceptions.html#BrokenPipeError) и\\n[`ConnectionResetError`](https://python-all.ru/3.6/library/exceptions.html#ConnectionResetError).150151#### `send_signal(signal)`152153Отправляет сигнал *signal* дочернему процессу.154155> **Примечание**156>157> В Windows `SIGTERM` является псевдонимом для [`terminate()`](https://python-all.ru/3.6/library/asyncio-subprocess.html#asyncio.asyncio.subprocess.Process.terminate). `CTRL_C_EVENT` и `CTRL_BREAK_EVENT` могут быть отправлены процессам, запущенным с параметром *creationflags*, который содержит `CREATE_NEW_PROCESS_GROUP`.158159#### `terminate()`160161Остановить дочерний процесс. В POSIX-системах метод отправляет `signal.SIGTERM`\\nдочернему процессу. В Windows для остановки дочернего процесса вызывается функция Win32 API\\n`TerminateProcess()`.162163#### `kill()`164165Убить дочерний процесс. В POSIX-системах функция отправляет `SIGKILL`\\nдочернему процессу. В Windows [`kill()`](https://python-all.ru/3.6/library/asyncio-subprocess.html#asyncio.asyncio.subprocess.Process.kill) является псевдонимом для [`terminate()`](https://python-all.ru/3.6/library/asyncio-subprocess.html#asyncio.asyncio.subprocess.Process.terminate).166167#### `stdin`168169Поток стандартного ввода ([`StreamWriter`](https://python-all.ru/3.6/library/asyncio-stream.html#asyncio.StreamWriter)), `None` если процесс\\nбыл создан с `stdin=None`.170171#### `stdout`172173Поток стандартного вывода ([`StreamReader`](https://python-all.ru/3.6/library/asyncio-stream.html#asyncio.StreamReader)), `None` если процесс\\nбыл создан с `stdout=None`.174175#### `stderr`176177Поток стандартного вывода ошибок ([`StreamReader`](https://python-all.ru/3.6/library/asyncio-stream.html#asyncio.StreamReader)), `None` если процесс\\nбыл создан с `stderr=None`.178179> **Предупреждение**180>181> Используйте метод [`communicate()`](https://python-all.ru/3.6/library/asyncio-subprocess.html#asyncio.asyncio.subprocess.Process.communicate) вместо [`.stdin.write`](https://python-all.ru/3.6/library/asyncio-subprocess.html#asyncio.asyncio.subprocess.Process.stdin), [`.stdout.read`](https://python-all.ru/3.6/library/asyncio-subprocess.html#asyncio.asyncio.subprocess.Process.stdout) или [`.stderr.read`](https://python-all.ru/3.6/library/asyncio-subprocess.html#asyncio.asyncio.subprocess.Process.stderr),\\nчтобы избежать взаимоблокировок из-за приостановки чтения или записи потоков и блокировки\\nдочернего процесса.182183#### `pid`184185Идентификатор процесса.186187Обратите внимание: для процессов, созданных функцией [`create_subprocess_shell()`](https://python-all.ru/3.6/library/asyncio-subprocess.html#asyncio.create_subprocess_shell),\\nэтот атрибут является идентификатором процесса запущенной оболочки.188189#### `returncode`190191Код возврата процесса при его завершении. Значение `None` указывает,\\nчто процесс ещё не завершён.192193Отрицательное значение `-N` указывает, что дочерний процесс был завершён сигналом\\n`N` (только Unix).194195## 18.5.6.6. Подпроцессы и потоки196197asyncio поддерживает запуск подпроцессов из разных потоков, но есть ограничения:198199- Цикл событий должен выполняться в главном потоке.200- Дочерний наблюдатель должен быть создан в главном потоке до запуска подпроцессов из других потоков. Вызовите функцию `get_child_watcher()` в главном потоке для создания дочернего наблюдателя.201202Класс [`asyncio.subprocess.Process`](https://python-all.ru/3.6/library/asyncio-subprocess.html#asyncio.asyncio.subprocess.Process) не является потокобезопасным.203204> **См. также**205>206> Раздел [Конкурентность и многопоточность в asyncio](https://python-all.ru/3.6/library/asyncio-dev.html#asyncio-multithreading).207208## 18.5.6.7. Примеры подпроцессов209210### 18.5.6.7.1. Подпроцесс с использованием транспорта и протокола211212Пример протокола подпроцесса, используемого для получения вывода подпроцесса и ожидания его завершения. Подпроцесс создаётся методом [`AbstractEventLoop.subprocess_exec()`](https://python-all.ru/3.6/library/asyncio-subprocess.html#asyncio.AbstractEventLoop.subprocess_exec):213214```python215import asyncio216import sys217218class DateProtocol(asyncio.SubprocessProtocol):219 def __init__(self, exit_future):220 self.exit_future = exit_future221 self.output = bytearray()222223 def pipe_data_received(self, fd, data):224 self.output.extend(data)225226 def process_exited(self):227 self.exit_future.set_result(True)228229@asyncio.coroutine230def get_date(loop):231 code = 'import datetime; print(datetime.datetime.now())'232 exit_future = asyncio.Future(loop=loop)233234 # Создать подпроцесс, управляемый протоколом DateProtocol,235 # перенаправить стандартный вывод в канал236 create = loop.subprocess_exec(lambda: DateProtocol(exit_future),237 sys.executable, '-c', code,238 stdin=None, stderr=None)239 transport, protocol = yield from create240241 # Ожидать завершения подпроцесса с помощью метода process_exited()242 # протокола243 yield from exit_future244245 # Закрыть канал stdout246 transport.close()247248 # Прочитать вывод, собранный методом pipe_data_received()249 # протокола250 data = bytes(protocol.output)251 return data.decode('ascii').rstrip()252253if sys.platform == "win32":254 loop = asyncio.ProactorEventLoop()255 asyncio.set_event_loop(loop)256else:257 loop = asyncio.get_event_loop()258259date = loop.run_until_complete(get_date(loop))260print("Current date: %s" % date)261loop.close()262```263264### 18.5.6.7.2. Подпроцесс с использованием потоков данных265266Пример использования класса [`Process`](https://python-all.ru/3.6/library/asyncio-subprocess.html#asyncio.asyncio.subprocess.Process) для управления подпроцессом и класса [`StreamReader`](https://python-all.ru/3.6/library/asyncio-stream.html#asyncio.StreamReader) для чтения из стандартного вывода. Подпроцесс создаётся функцией [`create_subprocess_exec()`](https://python-all.ru/3.6/library/asyncio-subprocess.html#asyncio.create_subprocess_exec):267268```python269import asyncio.subprocess270import sys271272@asyncio.coroutine273def get_date():274 code = 'import datetime; print(datetime.datetime.now())'275276 # Создать подпроцесс, перенаправив стандартный вывод в канал277 create = asyncio.create_subprocess_exec(sys.executable, '-c', code,278 stdout=asyncio.subprocess.PIPE)279 proc = yield from create280281 # Прочитать одну строку вывода282 data = yield from proc.stdout.readline()283 line = data.decode('ascii').rstrip()284285 # Ожидать завершения подпроцесса286 yield from proc.wait()287 return line288289if sys.platform == "win32":290 loop = asyncio.ProactorEventLoop()291 asyncio.set_event_loop(loop)292else:293 loop = asyncio.get_event_loop()294295date = loop.run_until_complete(get_date())296print("Current date: %s" % date)297loop.close()298```299