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

asyncio-subprocess.md

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

1> **Источник:** https://python-all.ru/3.10/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.10/Lib/asyncio/subprocess.py), [Lib/asyncio/base\_subprocess.py](https://python-all.ru/src/3.10/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.10/library/asyncio-subprocess.html#examples).5758## Создание подпроцессов5960#### `coroutine asyncio.create_subprocess_exec(program, *args, stdin=None, stdout=None, stderr=None, limit=None, **kwds)`6162Создание подпроцесса.6364Аргумент *limit* устанавливает ограничение буфера для обёрток [`StreamReader`](https://python-all.ru/3.10/library/asyncio-stream.html#asyncio.StreamReader) для `Process.stdout` и `Process.stderr` (если [`subprocess.PIPE`](https://python-all.ru/3.10/library/subprocess.html#subprocess.PIPE) передаётся в аргументы *stdout* и *stderr*).6566Возвращает экземпляр [`Process`](https://python-all.ru/3.10/library/asyncio-subprocess.html#asyncio.subprocess.Process).6768См. документацию [`loop.subprocess_exec()`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.loop.subprocess_exec) для других параметров.6970Изменено в версии 3.10: Удалён параметр *loop*.7172#### `coroutine asyncio.create_subprocess_shell(cmd, stdin=None, stdout=None, stderr=None, limit=None, **kwds)`7374Выполняет команду оболочки *cmd*.7576Аргумент *limit* устанавливает ограничение буфера для обёрток [`StreamReader`](https://python-all.ru/3.10/library/asyncio-stream.html#asyncio.StreamReader) для `Process.stdout` и `Process.stderr` (если [`subprocess.PIPE`](https://python-all.ru/3.10/library/subprocess.html#subprocess.PIPE) передаётся в аргументы *stdout* и *stderr*).7778Возвращает экземпляр [`Process`](https://python-all.ru/3.10/library/asyncio-subprocess.html#asyncio.subprocess.Process).7980См. документацию [`loop.subprocess_shell()`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.loop.subprocess_shell) для других параметров.8182> **Важно**83>84> На приложении лежит ответственность за то, чтобы все пробельные и специальные символы были экранированы должным образом для предотвращения уязвимостей [внедрения команд оболочки](https://python-all.ru/3.10/library/asyncio-subprocess.html). Функция [`shlex.quote()`](https://python-all.ru/3.10/library/shlex.html#shlex.quote) может использоваться для правильного экранирования пробельных и специальных символов оболочки в строках, которые будут использоваться для построения команд оболочки.8586Изменено в версии 3.10: Удалён параметр *loop*.8788> **Примечание**89>90> Подпроцессы доступны в Windows, если используется [`ProactorEventLoop`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.ProactorEventLoop). Подробнее см. [Поддержка подпроцессов в Windows](https://python-all.ru/3.10/library/asyncio-platforms.html#asyncio-windows-subprocess).9192> **См. также**93>94> asyncio также предоставляет следующие *низкоуровневые* API для работы с подпроцессами: [`loop.subprocess_exec()`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.loop.subprocess_exec), [`loop.subprocess_shell()`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.loop.subprocess_shell), [`loop.connect_read_pipe()`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.loop.connect_read_pipe), [`loop.connect_write_pipe()`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.loop.connect_write_pipe), а также [Транспорты подпроцессов](https://python-all.ru/3.10/library/asyncio-protocol.html#asyncio-subprocess-transports) и [Протоколы подпроцессов](https://python-all.ru/3.10/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.10/library/asyncio-subprocess.html#asyncio.subprocess.Process.stdin) будет указывать на экземпляр `StreamWriter`.103104Если *PIPE* передаётся в аргументы *stdout* или *stderr*, то атрибуты [`Process.stdout`](https://python-all.ru/3.10/library/asyncio-subprocess.html#asyncio.subprocess.Process.stdout) и [`Process.stderr`](https://python-all.ru/3.10/library/asyncio-subprocess.html#asyncio.subprocess.Process.stderr) будут указывать на экземпляры `StreamReader`.105106#### `asyncio.subprocess.STDOUT`107108Специальное значение, которое можно использовать в качестве аргумента *stderr*, указывающее, что стандартный поток ошибок должен быть перенаправлен в стандартный вывод.109110#### `asyncio.subprocess.DEVNULL`111112Специальное значение, которое можно использовать в качестве аргумента *stdin*, *stdout* или *stderr* для функций создания процессов. Оно указывает, что для соответствующего потока подпроцесса будет использован специальный файл [`os.devnull`](https://python-all.ru/3.10/library/os.html#os.devnull).113114## Взаимодействие с подпроцессами115116Функции [`create_subprocess_exec()`](https://python-all.ru/3.10/library/asyncio-subprocess.html#asyncio.create_subprocess_exec) и [`create_subprocess_shell()`](https://python-all.ru/3.10/library/asyncio-subprocess.html#asyncio.create_subprocess_shell) возвращают экземпляры класса *Process*. *Process* – это высокоуровневая обёртка, которая позволяет взаимодействовать с подпроцессами и отслеживать их завершение.117118#### `class asyncio.subprocess.Process`119120Объект, который оборачивает процессы ОС, созданные функциями `create_subprocess_exec()` и `create_subprocess_shell()`.121122Этот класс спроектирован с API, похожим на класс [`subprocess.Popen`](https://python-all.ru/3.10/library/subprocess.html#subprocess.Popen), но есть некоторые существенные отличия:123124- в отличие от Popen, экземпляры Process не имеют эквивалента методу [`poll()`](https://python-all.ru/3.10/library/subprocess.html#subprocess.Popen.poll);125- методы [`communicate()`](https://python-all.ru/3.10/library/asyncio-subprocess.html#asyncio.subprocess.Process.communicate) и [`wait()`](https://python-all.ru/3.10/library/asyncio-subprocess.html#asyncio.subprocess.Process.wait) не имеют параметра *timeout*: используйте функцию [`wait_for()`](https://python-all.ru/3.10/library/asyncio-task.html#asyncio.wait_for);126- метод [`Process.wait()`](https://python-all.ru/3.10/library/asyncio-subprocess.html#asyncio.subprocess.Process.wait) является асинхронным, тогда как метод [`subprocess.Popen.wait()`](https://python-all.ru/3.10/library/subprocess.html#subprocess.Popen.wait) реализован как блокирующий цикл ожидания;127- параметр *universal\_newlines* не поддерживается.128129This class is [не является потокобезопасным](https://python-all.ru/3.10/library/asyncio-dev.html#asyncio-multithreading).130131См. также раздел [Подпроцессы и потоки](https://python-all.ru/3.10/library/asyncio-subprocess.html#asyncio-subprocess-threads) .132133#### `coroutine wait()`134135Ожидает завершения дочернего процесса.136137Устанавливает и возвращает атрибут [`returncode`](https://python-all.ru/3.10/library/asyncio-subprocess.html#asyncio.subprocess.Process.returncode).138139> **Примечание**140>141> Этот метод может привести к взаимоблокировке при использовании `stdout=PIPE` или `stderr=PIPE`, если дочерний процесс генерирует настолько много вывода, что он блокируется в ожидании, пока буфер системного канала (pipe) примет больше данных. Во избежание этой ситуации используйте метод [`communicate()`](https://python-all.ru/3.10/library/asyncio-subprocess.html#asyncio.subprocess.Process.communicate) при работе с каналами.142143#### `coroutine communicate(input=None)`144145Взаимодействие с процессом:1461471. отправляет данные в *stdin* (если *input* не равен `None`);1482. читает данные из *stdout* и *stderr* до достижения конца файла (EOF);1493. ожидает завершения процесса.150151Необязательный аргумент *input* – это данные (объект [`bytes`](https://python-all.ru/3.10/library/stdtypes.html#bytes)), которые будут отправлены дочернему процессу.152153Возвращает кортеж `(stdout_data, stderr_data)`.154155Если возникает исключение [`BrokenPipeError`](https://python-all.ru/3.10/library/exceptions.html#BrokenPipeError) или [`ConnectionResetError`](https://python-all.ru/3.10/library/exceptions.html#ConnectionResetError) при записи *input* в *stdin*, это исключение игнорируется. Такая ситуация возникает, когда процесс завершается до того, как все данные будут записаны в *stdin*.156157Если требуется отправить данные в *stdin* процесса, процесс должен быть создан с `stdin=PIPE`. Аналогично, чтобы получить в результирующем кортеже что-то, отличное от `None`, процесс должен быть создан с аргументами `stdout=PIPE` и/или `stderr=PIPE`.158159Обратите внимание, что прочитанные данные буферизуются в памяти, поэтому не используйте этот метод, если размер данных велик или неограничен.160161#### `send_signal(signal)`162163Отправляет сигнал *signal* дочернему процессу.164165> **Примечание**166>167> В Windows `SIGTERM` является псевдонимом для [`terminate()`](https://python-all.ru/3.10/library/asyncio-subprocess.html#asyncio.subprocess.Process.terminate). `CTRL_C_EVENT` и `CTRL_BREAK_EVENT` могут быть отправлены процессам, запущенным с параметром *creationflags*, который содержит `CREATE_NEW_PROCESS_GROUP`.168169#### `terminate()`170171Останавливает дочерний процесс.172173В системах POSIX этот метод отправляет [`signal.SIGTERM`](https://python-all.ru/3.10/library/signal.html#signal.SIGTERM) дочернему процессу.174175В Windows для остановки дочернего процесса вызывается функция Win32 API `TerminateProcess()`.176177#### `kill()`178179Завершает дочерний процесс.180181В системах POSIX этот метод отправляет `SIGKILL` дочернему процессу.182183В Windows этот метод является псевдонимом для [`terminate()`](https://python-all.ru/3.10/library/asyncio-subprocess.html#asyncio.subprocess.Process.terminate).184185#### `stdin`186187Поток стандартного ввода (`StreamWriter`) или `None`, если процесс был создан с `stdin=None`.188189#### `stdout`190191Поток стандартного вывода (`StreamReader`) или `None`, если процесс был создан с `stdout=None`.192193#### `stderr`194195Поток стандартного вывода ошибок (`StreamReader`) или `None`, если процесс был создан с `stderr=None`.196197> **Предупреждение**198>199> Используйте метод [`communicate()`](https://python-all.ru/3.10/library/asyncio-subprocess.html#asyncio.subprocess.Process.communicate) вместо [`process.stdin.write()`](https://python-all.ru/3.10/library/asyncio-subprocess.html#asyncio.subprocess.Process.stdin), [`await process.stdout.read()`](https://python-all.ru/3.10/library/asyncio-subprocess.html#asyncio.subprocess.Process.stdout) или [`await process.stderr.read()`](https://python-all.ru/3.10/library/asyncio-subprocess.html#asyncio.subprocess.Process.stderr). Это позволяет избежать взаимоблокировок, возникающих из-за приостановки чтения или записи потоков и блокировки дочернего процесса.200201#### `pid`202203Идентификатор процесса (PID).204205Обратите внимание: для процессов, созданных функцией `create_subprocess_shell()`, этот атрибут содержит PID запущенной оболочки.206207#### `returncode`208209Код возврата процесса при его завершении.210211Значение `None` указывает на то, что процесс ещё не завершён.212213Отрицательное значение `-N` означает, что дочерний процесс был завершён по сигналу `N` (только POSIX).214215### Подпроцессы и потоки216217Стандартный цикл событий asyncio поддерживает запуск подпроцессов из разных потоков по умолчанию.218219В Windows подпроцессы поддерживаются только [`ProactorEventLoop`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.ProactorEventLoop) (по умолчанию), [`SelectorEventLoop`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.SelectorEventLoop) не поддерживает подпроцессы.220221В UNIX *наблюдатели дочерних процессов* используются для ожидания завершения подпроцессов, см. [Наблюдатели процессов](https://python-all.ru/3.10/library/asyncio-policy.html#asyncio-watchers) для получения дополнительной информации.222223Изменено в версии 3.8: UNIX перешёл на использование [`ThreadedChildWatcher`](https://python-all.ru/3.10/library/asyncio-policy.html#asyncio.ThreadedChildWatcher) для запуска подпроцессов из разных потоков без каких-либо ограничений.224225Запуск подпроцесса с *неактивным* текущим наблюдателем дочерних процессов вызывает [`RuntimeError`](https://python-all.ru/3.10/library/exceptions.html#RuntimeError).226227Обратите внимание: альтернативные реализации цикла событий могут иметь собственные ограничения; обратитесь к их документации.228229> **См. также**230>231> Раздел [Конкурентность и многопоточность в asyncio](https://python-all.ru/3.10/library/asyncio-dev.html#asyncio-multithreading).232233### Примеры234235Пример использования класса [`Process`](https://python-all.ru/3.10/library/asyncio-subprocess.html#asyncio.subprocess.Process) для управления подпроцессом и класса [`StreamReader`](https://python-all.ru/3.10/library/asyncio-stream.html#asyncio.StreamReader) для чтения из его стандартного вывода.236237Подпроцесс создаётся функцией [`create_subprocess_exec()`](https://python-all.ru/3.10/library/asyncio-subprocess.html#asyncio.create_subprocess_exec):238239```python240import asyncio241import sys242243async def get_date():244    code = 'import datetime; print(datetime.datetime.now())'245246    # Создать подпроцесс; перенаправить стандартный вывод247    # в канал.248    proc = await asyncio.create_subprocess_exec(249        sys.executable, '-c', code,250        stdout=asyncio.subprocess.PIPE)251252    # Прочитать одну строку вывода.253    data = await proc.stdout.readline()254    line = data.decode('ascii').rstrip()255256    # Дождаться завершения подпроцесса.257    await proc.wait()258    return line259260date = asyncio.run(get_date())261print(f"Current date: {date}")262```263264См. также [тот же пример](https://python-all.ru/3.10/library/asyncio-protocol.html#asyncio-example-subprocess-proto), написанный с использованием низкоуровневых API.265