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

asyncio-subprocess.md

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

1> **Источник:** https://python-all.ru/3.7/library/asyncio-subprocess.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# Подпроцессы89В этом разделе описываются высокоуровневые async/await asyncio API для создания и управления подпроцессами.1011Вот пример того, как asyncio может выполнить команду оболочки и получить её результат:1213```python14import asyncio1516async def run(cmd):17    proc = await asyncio.create_subprocess_shell(18        cmd,19        stdout=asyncio.subprocess.PIPE,20        stderr=asyncio.subprocess.PIPE)2122    stdout, stderr = await proc.communicate()2324    print(f'[{cmd!r} exited with {proc.returncode}]')25    if stdout:26        print(f'[stdout]\n{stdout.decode()}')27    if stderr:28        print(f'[stderr]\n{stderr.decode()}')2930asyncio.run(run('ls /zzz'))31```3233выведет:3435```python36['ls /zzz' exited with 1]37[stderr]38ls: /zzz: No such file or directory39```4041Поскольку все функции asyncio для работы с подпроцессами являются асинхронными, и asyncio предоставляет множество инструментов для работы с такими функциями, легко выполнять и контролировать несколько подпроцессов параллельно. Действительно, тривиально изменить пример выше, чтобы запустить несколько команд одновременно:4243```python44async def main():45    await asyncio.gather(46        run('ls /zzz'),47        run('sleep 1; echo "hello"'))4849asyncio.run(main())50```5152См. также подраздел [Примеры](https://python-all.ru/3.7/library/asyncio-subprocess.html#examples).5354## Создание подпроцессов5556#### `coroutine asyncio.create_subprocess_exec(program, *args, stdin=None, stdout=None, stderr=None, loop=None, limit=None, **kwds)`5758Создание подпроцесса.5960Аргумент *limit* устанавливает ограничение буфера для обёрток [`StreamReader`](https://python-all.ru/3.7/library/asyncio-stream.html#asyncio.StreamReader) для `Process.stdout` и `Process.stderr` (если [`subprocess.PIPE`](https://python-all.ru/3.7/library/subprocess.html#subprocess.PIPE) передаётся в аргументы *stdout* и *stderr*).6162Возвращает экземпляр [`Process`](https://python-all.ru/3.7/library/asyncio-subprocess.html#asyncio.asyncio.subprocess.Process).6364См. документацию [`loop.subprocess_exec()`](https://python-all.ru/3.7/library/asyncio-eventloop.html#asyncio.loop.subprocess_exec) для других параметров.6566#### `coroutine asyncio.create_subprocess_shell(cmd, stdin=None, stdout=None, stderr=None, loop=None, limit=None, **kwds)`6768Выполняет команду оболочки *cmd*.6970Аргумент *limit* устанавливает ограничение буфера для обёрток [`StreamReader`](https://python-all.ru/3.7/library/asyncio-stream.html#asyncio.StreamReader) для `Process.stdout` и `Process.stderr` (если [`subprocess.PIPE`](https://python-all.ru/3.7/library/subprocess.html#subprocess.PIPE) передаётся в аргументы *stdout* и *stderr*).7172Возвращает экземпляр [`Process`](https://python-all.ru/3.7/library/asyncio-subprocess.html#asyncio.asyncio.subprocess.Process).7374См. документацию [`loop.subprocess_shell()`](https://python-all.ru/3.7/library/asyncio-eventloop.html#asyncio.loop.subprocess_shell) для других параметров.7576> **Важно**77>78> На приложении лежит ответственность за то, чтобы все пробельные и специальные символы были экранированы должным образом для предотвращения уязвимостей [внедрения команд оболочки](https://python-all.ru/3.7/library/asyncio-subprocess.html). Функция [`shlex.quote()`](https://python-all.ru/3.7/library/shlex.html#shlex.quote) может использоваться для правильного экранирования пробельных и специальных символов оболочки в строках, которые будут использоваться для построения команд оболочки.7980> **Примечание**81>82> Реализация цикла событий asyncio по умолчанию в **Windows** не поддерживает подпроцессы. Подпроцессы доступны в Windows, если используется [`ProactorEventLoop`](https://python-all.ru/3.7/library/asyncio-eventloop.html#asyncio.ProactorEventLoop). См. [Поддержка подпроцессов в Windows](https://python-all.ru/3.7/library/asyncio-platforms.html#asyncio-windows-subprocess) для подробностей.8384> **См. также**85>86> asyncio также предоставляет следующие *низкоуровневые* API для работы с подпроцессами: [`loop.subprocess_exec()`](https://python-all.ru/3.7/library/asyncio-eventloop.html#asyncio.loop.subprocess_exec), [`loop.subprocess_shell()`](https://python-all.ru/3.7/library/asyncio-eventloop.html#asyncio.loop.subprocess_shell), [`loop.connect_read_pipe()`](https://python-all.ru/3.7/library/asyncio-eventloop.html#asyncio.loop.connect_read_pipe), [`loop.connect_write_pipe()`](https://python-all.ru/3.7/library/asyncio-eventloop.html#asyncio.loop.connect_write_pipe), а также [Транспорты подпроцессов](https://python-all.ru/3.7/library/asyncio-protocol.html#asyncio-subprocess-transports) и [Протоколы подпроцессов](https://python-all.ru/3.7/library/asyncio-protocol.html#asyncio-subprocess-protocols).8788## Константы8990#### `asyncio.subprocess.PIPE`9192Может быть передан в параметры *stdin*, *stdout* или *stderr*.9394Если *PIPE* передаётся в аргумент *stdin*, то атрибут [`Process.stdin`](https://python-all.ru/3.7/library/asyncio-subprocess.html#asyncio.asyncio.subprocess.Process.stdin) будет указывать на экземпляр [`StreamWriter`](https://python-all.ru/3.7/library/asyncio-stream.html#asyncio.StreamWriter).9596Если *PIPE* передаётся в аргументы *stdout* или *stderr*, то атрибуты [`Process.stdout`](https://python-all.ru/3.7/library/asyncio-subprocess.html#asyncio.asyncio.subprocess.Process.stdout) и [`Process.stderr`](https://python-all.ru/3.7/library/asyncio-subprocess.html#asyncio.asyncio.subprocess.Process.stderr) будут указывать на экземпляры [`StreamReader`](https://python-all.ru/3.7/library/asyncio-stream.html#asyncio.StreamReader).9798#### `asyncio.subprocess.STDOUT`99100Специальное значение, которое можно использовать в качестве аргумента *stderr*, указывающее, что стандартный поток ошибок должен быть перенаправлен в стандартный вывод.101102#### `asyncio.subprocess.DEVNULL`103104Специальное значение, которое можно использовать в качестве аргумента *stdin*, *stdout* или *stderr* для функций создания процессов. Оно указывает, что для соответствующего потока подпроцесса будет использован специальный файл [`os.devnull`](https://python-all.ru/3.7/library/os.html#os.devnull).105106## Взаимодействие с подпроцессами107108Функции [`create_subprocess_exec()`](https://python-all.ru/3.7/library/asyncio-subprocess.html#asyncio.create_subprocess_exec) и [`create_subprocess_shell()`](https://python-all.ru/3.7/library/asyncio-subprocess.html#asyncio.create_subprocess_shell) возвращают экземпляры класса *Process*. *Process* – это высокоуровневая обёртка, которая позволяет взаимодействовать с подпроцессами и отслеживать их завершение.109110#### `class asyncio.subprocess.Process`111112Объект, который оборачивает процессы ОС, созданные функциями [`create_subprocess_exec()`](https://python-all.ru/3.7/library/asyncio-subprocess.html#asyncio.create_subprocess_exec) и [`create_subprocess_shell()`](https://python-all.ru/3.7/library/asyncio-subprocess.html#asyncio.create_subprocess_shell).113114Этот класс спроектирован с API, похожим на класс [`subprocess.Popen`](https://python-all.ru/3.7/library/subprocess.html#subprocess.Popen), но есть некоторые существенные отличия:115116- в отличие от Popen, экземпляры Process не имеют эквивалента методу [`poll()`](https://python-all.ru/3.7/library/subprocess.html#subprocess.Popen.poll);117- методы [`communicate()`](https://python-all.ru/3.7/library/asyncio-subprocess.html#asyncio.asyncio.subprocess.Process.communicate) и [`wait()`](https://python-all.ru/3.7/library/asyncio-subprocess.html#asyncio.asyncio.subprocess.Process.wait) не имеют параметра *timeout*: используйте функцию [`wait_for()`](https://python-all.ru/3.7/library/asyncio-task.html#asyncio.wait_for);118- метод [`Process.wait()`](https://python-all.ru/3.7/library/asyncio-subprocess.html#asyncio.asyncio.subprocess.Process.wait) является асинхронным, тогда как метод [`subprocess.Popen.wait()`](https://python-all.ru/3.7/library/subprocess.html#subprocess.Popen.wait) реализован как блокирующий цикл ожидания;119- параметр *universal\_newlines* не поддерживается.120121This class is [не является потокобезопасным](https://python-all.ru/3.7/library/asyncio-dev.html#asyncio-multithreading).122123См. также раздел [Подпроцессы и потоки](https://python-all.ru/3.7/library/asyncio-subprocess.html#asyncio-subprocess-threads) .124125#### `coroutine wait()`126127Ожидает завершения дочернего процесса.128129Устанавливает и возвращает атрибут [`returncode`](https://python-all.ru/3.7/library/asyncio-subprocess.html#asyncio.asyncio.subprocess.Process.returncode).130131> **Примечание**132>133> Этот метод может привести к взаимоблокировке при использовании `stdout=PIPE` или `stderr=PIPE`, если дочерний процесс генерирует настолько много вывода, что он блокируется в ожидании, пока буфер системного канала (pipe) примет больше данных. Во избежание этой ситуации используйте метод [`communicate()`](https://python-all.ru/3.7/library/asyncio-subprocess.html#asyncio.asyncio.subprocess.Process.communicate) при работе с каналами.134135#### `coroutine communicate(input=None)`136137Взаимодействие с процессом:1381391. отправляет данные в *stdin* (если *input* не равен `None`);1402. читает данные из *stdout* и *stderr* до достижения конца файла (EOF);1413. ожидает завершения процесса.142143Необязательный аргумент *input* – это данные (объект [`bytes`](https://python-all.ru/3.7/library/stdtypes.html#bytes)), которые будут отправлены дочернему процессу.144145Возвращает кортеж `(stdout_data, stderr_data)`.146147Если возникает исключение [`BrokenPipeError`](https://python-all.ru/3.7/library/exceptions.html#BrokenPipeError) или [`ConnectionResetError`](https://python-all.ru/3.7/library/exceptions.html#ConnectionResetError) при записи *input* в *stdin*, это исключение игнорируется. Такая ситуация возникает, когда процесс завершается до того, как все данные будут записаны в *stdin*.148149Если требуется отправить данные в *stdin* процесса, процесс должен быть создан с `stdin=PIPE`. Аналогично, чтобы получить в результирующем кортеже что-то, отличное от `None`, процесс должен быть создан с аргументами `stdout=PIPE` и/или `stderr=PIPE`.150151Обратите внимание, что прочитанные данные буферизуются в памяти, поэтому не используйте этот метод, если размер данных велик или неограничен.152153#### `send_signal(signal)`154155Отправляет сигнал *signal* дочернему процессу.156157> **Примечание**158>159> В Windows `SIGTERM` является псевдонимом для [`terminate()`](https://python-all.ru/3.7/library/asyncio-subprocess.html#asyncio.asyncio.subprocess.Process.terminate). `CTRL_C_EVENT` и `CTRL_BREAK_EVENT` могут быть отправлены процессам, запущенным с параметром *creationflags*, который содержит `CREATE_NEW_PROCESS_GROUP`.160161#### `terminate()`162163Останавливает дочерний процесс.164165В системах POSIX этот метод отправляет [`signal.SIGTERM`](https://python-all.ru/3.7/library/signal.html#signal.SIGTERM) дочернему процессу.166167В Windows для остановки дочернего процесса вызывается функция Win32 API `TerminateProcess()`.168169#### `kill()`170171Убить дочерний процесс.172173В системах POSIX этот метод отправляет `SIGKILL` дочернему процессу.174175В Windows этот метод является псевдонимом для [`terminate()`](https://python-all.ru/3.7/library/asyncio-subprocess.html#asyncio.asyncio.subprocess.Process.terminate).176177#### `stdin`178179Поток стандартного ввода ([`StreamWriter`](https://python-all.ru/3.7/library/asyncio-stream.html#asyncio.StreamWriter)) или `None`, если процесс был создан с `stdin=None`.180181#### `stdout`182183Поток стандартного вывода ([`StreamReader`](https://python-all.ru/3.7/library/asyncio-stream.html#asyncio.StreamReader)) или `None`, если процесс был создан с `stdout=None`.184185#### `stderr`186187Поток стандартного вывода ошибок ([`StreamReader`](https://python-all.ru/3.7/library/asyncio-stream.html#asyncio.StreamReader)) или `None`, если процесс был создан с `stderr=None`.188189> **Предупреждение**190>191> Используйте метод [`communicate()`](https://python-all.ru/3.7/library/asyncio-subprocess.html#asyncio.asyncio.subprocess.Process.communicate) вместо [`process.stdin.write()`](https://python-all.ru/3.7/library/asyncio-subprocess.html#asyncio.asyncio.subprocess.Process.stdin), [`await process.stdout.read()`](https://python-all.ru/3.7/library/asyncio-subprocess.html#asyncio.asyncio.subprocess.Process.stdout) или [`await process.stderr.read`](https://python-all.ru/3.7/library/asyncio-subprocess.html#asyncio.asyncio.subprocess.Process.stderr). Это позволяет избежать взаимоблокировок, возникающих из-за приостановки чтения или записи потоков и блокировки дочернего процесса.192193#### `pid`194195Идентификатор процесса (PID).196197Обратите внимание: для процессов, созданных функцией [`create_subprocess_shell()`](https://python-all.ru/3.7/library/asyncio-subprocess.html#asyncio.create_subprocess_shell), этот атрибут содержит PID запущенной оболочки.198199#### `returncode`200201Код возврата процесса при его завершении.202203Значение `None` указывает на то, что процесс ещё не завершён.204205Отрицательное значение `-N` означает, что дочерний процесс был завершён по сигналу `N` (только POSIX).206207### Подпроцессы и потоки208209Стандартный цикл событий asyncio поддерживает запуск подпроцессов из разных потоков, но есть ограничения:210211- Цикл событий должен выполняться в главном потоке.212- Наблюдатель дочерних процессов должен быть создан в главном потоке перед запуском подпроцессов из других потоков. Вызовите функцию [`get_child_watcher()`](https://python-all.ru/3.7/library/asyncio-policy.html#asyncio.get_child_watcher) в главном потоке, чтобы создать наблюдатель дочерних процессов.213214Обратите внимание, что альтернативные реализации цикла событий могут не иметь указанных выше ограничений; обратитесь к их документации.215216> **См. также**217>218> Раздел [Конкурентность и многопоточность в asyncio](https://python-all.ru/3.7/library/asyncio-dev.html#asyncio-multithreading).219220### Примеры221222Пример использования класса [`Process`](https://python-all.ru/3.7/library/asyncio-subprocess.html#asyncio.asyncio.subprocess.Process) для управления подпроцессом и класса [`StreamReader`](https://python-all.ru/3.7/library/asyncio-stream.html#asyncio.StreamReader) для чтения из его стандартного вывода.223224Подпроцесс создаётся функцией [`create_subprocess_exec()`](https://python-all.ru/3.7/library/asyncio-subprocess.html#asyncio.create_subprocess_exec):225226```python227import asyncio228import sys229230async def get_date():231    code = 'import datetime; print(datetime.datetime.now())'232233    # Создать подпроцесс; перенаправить стандартный вывод234    # в канал.235    proc = await asyncio.create_subprocess_exec(236        sys.executable, '-c', code,237        stdout=asyncio.subprocess.PIPE)238239    # Прочитать одну строку вывода.240    data = await proc.stdout.readline()241    line = data.decode('ascii').rstrip()242243    # Дождаться завершения подпроцесса.244    await proc.wait()245    return line246247if sys.platform == "win32":248    asyncio.set_event_loop_policy(249        asyncio.WindowsProactorEventLoopPolicy())250251date = asyncio.run(get_date())252print(f"Current date: {date}")253```254255См. также [тот же пример](https://python-all.ru/3.7/library/asyncio-protocol.html#asyncio-example-subprocess-proto), написанный с использованием низкоуровневых API.256