Документация Python неофициальный перевод

asyncio-subprocess.md

268 строк · 21.2 КБ · обычная страница · сырой текст · скачать

1> **Источник:** https://python-all.ru/3.12/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.12/Lib/asyncio/subprocess.py), [Lib/asyncio/base\_subprocess.py](https://python-all.ru/src/3.12/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.12/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.12/library/asyncio-stream.html#asyncio.StreamReader) для [`stdout`](https://python-all.ru/3.12/library/asyncio-subprocess.html#asyncio.subprocess.Process.stdout) и [`stderr`](https://python-all.ru/3.12/library/asyncio-subprocess.html#asyncio.subprocess.Process.stderr) (если [`subprocess.PIPE`](https://python-all.ru/3.12/library/subprocess.html#subprocess.PIPE) передаётся в аргументы *stdout* и *stderr*).6566Возвращает экземпляр [`Process`](https://python-all.ru/3.12/library/asyncio-subprocess.html#asyncio.subprocess.Process).6768См. документацию [`loop.subprocess_exec()`](https://python-all.ru/3.12/library/asyncio-eventloop.html#asyncio.loop.subprocess_exec) для других параметров.6970Изменено в версии 3.10: Удалён параметр *loop*.7172#### `async asyncio.create_subprocess_shell(cmd, stdin=None, stdout=None, stderr=None, limit=None, **kwds)`7374Выполняет команду оболочки *cmd*.7576Аргумент *limit* устанавливает ограничение буфера для обёрток [`StreamReader`](https://python-all.ru/3.12/library/asyncio-stream.html#asyncio.StreamReader) для [`stdout`](https://python-all.ru/3.12/library/asyncio-subprocess.html#asyncio.subprocess.Process.stdout) и [`stderr`](https://python-all.ru/3.12/library/asyncio-subprocess.html#asyncio.subprocess.Process.stderr) (если [`subprocess.PIPE`](https://python-all.ru/3.12/library/subprocess.html#subprocess.PIPE) передаётся в аргументы *stdout* и *stderr*).7778Возвращает экземпляр [`Process`](https://python-all.ru/3.12/library/asyncio-subprocess.html#asyncio.subprocess.Process).7980См. документацию [`loop.subprocess_shell()`](https://python-all.ru/3.12/library/asyncio-eventloop.html#asyncio.loop.subprocess_shell) для других параметров.8182> **Важно**83>84> На приложении лежит ответственность за то, чтобы все пробельные и специальные символы были экранированы должным образом для предотвращения уязвимостей [внедрения команд оболочки](https://python-all.ru/3.12/library/asyncio-subprocess.html). Функция [`shlex.quote()`](https://python-all.ru/3.12/library/shlex.html#shlex.quote) может использоваться для правильного экранирования пробельных и специальных символов оболочки в строках, которые будут использоваться для построения команд оболочки.8586Изменено в версии 3.10: Удалён параметр *loop*.8788> **Примечание**89>90> Подпроцессы доступны в Windows, если используется [`ProactorEventLoop`](https://python-all.ru/3.12/library/asyncio-eventloop.html#asyncio.ProactorEventLoop). Подробнее см. [Поддержка подпроцессов в Windows](https://python-all.ru/3.12/library/asyncio-platforms.html#asyncio-windows-subprocess).9192> **См. также**93>94> asyncio также предоставляет следующие *низкоуровневые* API для работы с подпроцессами: [`loop.subprocess_exec()`](https://python-all.ru/3.12/library/asyncio-eventloop.html#asyncio.loop.subprocess_exec), [`loop.subprocess_shell()`](https://python-all.ru/3.12/library/asyncio-eventloop.html#asyncio.loop.subprocess_shell), [`loop.connect_read_pipe()`](https://python-all.ru/3.12/library/asyncio-eventloop.html#asyncio.loop.connect_read_pipe), [`loop.connect_write_pipe()`](https://python-all.ru/3.12/library/asyncio-eventloop.html#asyncio.loop.connect_write_pipe), а также [Транспорты подпроцессов](https://python-all.ru/3.12/library/asyncio-protocol.html#asyncio-subprocess-transports) и [Протоколы подпроцессов](https://python-all.ru/3.12/library/asyncio-protocol.html#asyncio-subprocess-protocols).9596## Константы9798#### `asyncio.subprocess.PIPE`99100Может быть передан в параметры *stdin*, *stdout* или *stderr*.101102Если *PIPE* передаётся в аргумент *stdin*, то атрибут [`Process.stdin`](https://python-all.ru/3.12/library/asyncio-subprocess.html#asyncio.subprocess.Process.stdin) будет указывать на экземпляр [`StreamWriter`](https://python-all.ru/3.12/library/asyncio-stream.html#asyncio.StreamWriter).103104Если *PIPE* передаётся в аргументы *stdout* или *stderr*, то атрибуты [`Process.stdout`](https://python-all.ru/3.12/library/asyncio-subprocess.html#asyncio.subprocess.Process.stdout) и [`Process.stderr`](https://python-all.ru/3.12/library/asyncio-subprocess.html#asyncio.subprocess.Process.stderr) будут указывать на экземпляры [`StreamReader`](https://python-all.ru/3.12/library/asyncio-stream.html#asyncio.StreamReader).105106#### `asyncio.subprocess.STDOUT`107108Специальное значение, которое можно использовать в качестве аргумента *stderr*, указывающее, что стандартный поток ошибок должен быть перенаправлен в стандартный вывод.109110#### `asyncio.subprocess.DEVNULL`111112Специальное значение, которое можно использовать в качестве аргумента *stdin*, *stdout* или *stderr* для функций создания процессов. Оно указывает, что для соответствующего потока подпроцесса будет использован специальный файл [`os.devnull`](https://python-all.ru/3.12/library/os.html#os.devnull).113114## Взаимодействие с подпроцессами115116Функции [`create_subprocess_exec()`](https://python-all.ru/3.12/library/asyncio-subprocess.html#asyncio.create_subprocess_exec) и [`create_subprocess_shell()`](https://python-all.ru/3.12/library/asyncio-subprocess.html#asyncio.create_subprocess_shell) возвращают экземпляры класса *Process*. *Process* – это высокоуровневая обёртка, которая позволяет взаимодействовать с подпроцессами и отслеживать их завершение.117118#### `class asyncio.subprocess.Process`119120Объект, который оборачивает процессы ОС, созданные функциями [`create_subprocess_exec()`](https://python-all.ru/3.12/library/asyncio-subprocess.html#asyncio.create_subprocess_exec) и [`create_subprocess_shell()`](https://python-all.ru/3.12/library/asyncio-subprocess.html#asyncio.create_subprocess_shell).121122Этот класс спроектирован с API, похожим на класс [`subprocess.Popen`](https://python-all.ru/3.12/library/subprocess.html#subprocess.Popen), но есть некоторые существенные отличия:123124- в отличие от Popen, экземпляры Process не имеют эквивалента методу [`poll()`](https://python-all.ru/3.12/library/subprocess.html#subprocess.Popen.poll);125- методы [`communicate()`](https://python-all.ru/3.12/library/asyncio-subprocess.html#asyncio.subprocess.Process.communicate) и [`wait()`](https://python-all.ru/3.12/library/asyncio-subprocess.html#asyncio.subprocess.Process.wait) не имеют параметра *timeout*: используйте функцию [`wait_for()`](https://python-all.ru/3.12/library/asyncio-task.html#asyncio.wait_for);126- метод [`Process.wait()`](https://python-all.ru/3.12/library/asyncio-subprocess.html#asyncio.subprocess.Process.wait) является асинхронным, тогда как метод [`subprocess.Popen.wait()`](https://python-all.ru/3.12/library/subprocess.html#subprocess.Popen.wait) реализован как блокирующий цикл ожидания;127- параметр *universal\_newlines* не поддерживается.128129This class is [не является потокобезопасным](https://python-all.ru/3.12/library/asyncio-dev.html#asyncio-multithreading).130131См. также раздел [Подпроцессы и потоки](https://python-all.ru/3.12/library/asyncio-subprocess.html#asyncio-subprocess-threads) .132133#### `async wait()`134135Ожидает завершения дочернего процесса.136137Устанавливает и возвращает атрибут [`returncode`](https://python-all.ru/3.12/library/asyncio-subprocess.html#asyncio.subprocess.Process.returncode).138139> **Примечание**140>141> Этот метод может привести к взаимоблокировке при использовании `stdout=PIPE` или `stderr=PIPE`, если дочерний процесс генерирует настолько много вывода, что он блокируется в ожидании, пока буфер системного канала (pipe) примет больше данных. Во избежание этой ситуации используйте метод [`communicate()`](https://python-all.ru/3.12/library/asyncio-subprocess.html#asyncio.subprocess.Process.communicate) при работе с каналами.142143#### `async communicate(input=None)`144145Взаимодействие с процессом:1461471. отправляет данные в *stdin* (если *input* не равен `None`);1482. закрывает *stdin*;1493. читает данные из *stdout* и *stderr* до достижения конца файла (EOF);1504. ожидает завершения процесса.151152Необязательный аргумент *input* – это данные (объект [`bytes`](https://python-all.ru/3.12/library/stdtypes.html#bytes)), которые будут отправлены дочернему процессу.153154Возвращает кортеж `(stdout_data, stderr_data)`.155156Если возникает исключение [`BrokenPipeError`](https://python-all.ru/3.12/library/exceptions.html#BrokenPipeError) или [`ConnectionResetError`](https://python-all.ru/3.12/library/exceptions.html#ConnectionResetError) при записи *input* в *stdin*, это исключение игнорируется. Такая ситуация возникает, когда процесс завершается до того, как все данные будут записаны в *stdin*.157158Если требуется отправить данные в *stdin* процесса, процесс должен быть создан с `stdin=PIPE`. Аналогично, чтобы получить в результирующем кортеже что-то, отличное от `None`, процесс должен быть создан с аргументами `stdout=PIPE` и/или `stderr=PIPE`.159160Обратите внимание, что прочитанные данные буферизуются в памяти, поэтому не используйте этот метод, если размер данных велик или неограничен.161162Изменено в версии 3.12: *stdin* также закрывается при `input=None`.163164#### `send_signal(signal)`165166Отправляет сигнал *signal* дочернему процессу.167168> **Примечание**169>170> В Windows [`SIGTERM`](https://python-all.ru/3.12/library/signal.html#signal.SIGTERM) является псевдонимом для [`terminate()`](https://python-all.ru/3.12/library/asyncio-subprocess.html#asyncio.subprocess.Process.terminate). `CTRL_C_EVENT` и `CTRL_BREAK_EVENT` могут быть отправлены процессам, запущенным с параметром *creationflags*, который содержит `CREATE_NEW_PROCESS_GROUP`.171172#### `terminate()`173174Останавливает дочерний процесс.175176В системах POSIX этот метод отправляет [`SIGTERM`](https://python-all.ru/3.12/library/signal.html#signal.SIGTERM) дочернему процессу.177178В Windows для остановки дочернего процесса вызывается функция Win32 API `TerminateProcess()`.179180#### `kill()`181182Завершает дочерний процесс.183184В системах POSIX этот метод отправляет [`SIGKILL`](https://python-all.ru/3.12/library/signal.html#signal.SIGKILL) дочернему процессу.185186В Windows этот метод является псевдонимом для [`terminate()`](https://python-all.ru/3.12/library/asyncio-subprocess.html#asyncio.subprocess.Process.terminate).187188#### `stdin`189190Поток стандартного ввода ([`StreamWriter`](https://python-all.ru/3.12/library/asyncio-stream.html#asyncio.StreamWriter)) или `None`, если процесс был создан с `stdin=None`.191192#### `stdout`193194Поток стандартного вывода ([`StreamReader`](https://python-all.ru/3.12/library/asyncio-stream.html#asyncio.StreamReader)) или `None`, если процесс был создан с `stdout=None`.195196#### `stderr`197198Поток стандартного вывода ошибок ([`StreamReader`](https://python-all.ru/3.12/library/asyncio-stream.html#asyncio.StreamReader)) или `None`, если процесс был создан с `stderr=None`.199200> **Предупреждение**201>202> Используйте метод [`communicate()`](https://python-all.ru/3.12/library/asyncio-subprocess.html#asyncio.subprocess.Process.communicate) вместо [`process.stdin.write()`](https://python-all.ru/3.12/library/asyncio-subprocess.html#asyncio.subprocess.Process.stdin), [`await process.stdout.read()`](https://python-all.ru/3.12/library/asyncio-subprocess.html#asyncio.subprocess.Process.stdout) или [`await process.stderr.read()`](https://python-all.ru/3.12/library/asyncio-subprocess.html#asyncio.subprocess.Process.stderr). Это позволяет избежать взаимоблокировок, возникающих из-за приостановки чтения или записи потоков и блокировки дочернего процесса.203204#### `pid`205206Идентификатор процесса (PID).207208Обратите внимание: для процессов, созданных функцией [`create_subprocess_shell()`](https://python-all.ru/3.12/library/asyncio-subprocess.html#asyncio.create_subprocess_shell), этот атрибут содержит PID запущенной оболочки.209210#### `returncode`211212Код возврата процесса при его завершении.213214Значение `None` указывает на то, что процесс ещё не завершён.215216Отрицательное значение `-N` означает, что дочерний процесс был завершён по сигналу `N` (только POSIX).217218### Подпроцессы и потоки219220Стандартный цикл событий asyncio поддерживает запуск подпроцессов из разных потоков по умолчанию.221222В Windows подпроцессы поддерживаются только [`ProactorEventLoop`](https://python-all.ru/3.12/library/asyncio-eventloop.html#asyncio.ProactorEventLoop) (по умолчанию), [`SelectorEventLoop`](https://python-all.ru/3.12/library/asyncio-eventloop.html#asyncio.SelectorEventLoop) не поддерживает подпроцессы.223224В UNIX *наблюдатели дочерних процессов* используются для ожидания завершения подпроцессов, см. [Наблюдатели процессов](https://python-all.ru/3.12/library/asyncio-policy.html#asyncio-watchers) для получения дополнительной информации.225226Изменено в версии 3.8: UNIX перешёл на использование [`ThreadedChildWatcher`](https://python-all.ru/3.12/library/asyncio-policy.html#asyncio.ThreadedChildWatcher) для запуска подпроцессов из разных потоков без каких-либо ограничений.227228Запуск подпроцесса с *неактивным* текущим наблюдателем дочерних процессов вызывает [`RuntimeError`](https://python-all.ru/3.12/library/exceptions.html#RuntimeError).229230Обратите внимание: альтернативные реализации цикла событий могут иметь собственные ограничения; обратитесь к их документации.231232> **См. также**233>234> Раздел [Конкурентность и многопоточность в asyncio](https://python-all.ru/3.12/library/asyncio-dev.html#asyncio-multithreading).235236### Примеры237238Пример использования класса [`Process`](https://python-all.ru/3.12/library/asyncio-subprocess.html#asyncio.subprocess.Process) для управления подпроцессом и класса [`StreamReader`](https://python-all.ru/3.12/library/asyncio-stream.html#asyncio.StreamReader) для чтения из его стандартного вывода.239240Подпроцесс создаётся функцией [`create_subprocess_exec()`](https://python-all.ru/3.12/library/asyncio-subprocess.html#asyncio.create_subprocess_exec):241242```python243import asyncio244import sys245246async def get_date():247    code = 'import datetime; print(datetime.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.12/library/asyncio-protocol.html#asyncio-example-subprocess-proto), написанный с использованием низкоуровневых API.268