SubprocessesПодпроцессы
Исходный код: Lib/asyncio/subprocess.py, Lib/asyncio/base_subprocess.py
В этом разделе описываются высокоуровневые API asyncio с async/await для создания и управления подпроцессами.
Вот пример того, как asyncio может выполнить команду оболочки и получить её результат:
import asyncio
async def run(cmd):
proc = await asyncio.create_subprocess_shell(
cmd,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE)
stdout, stderr = await proc.communicate()
print(f'[{cmd!r} exited with {proc.returncode}]')
if stdout:
print(f'[stdout]\n{stdout.decode()}')
if stderr:
print(f'[stderr]\n{stderr.decode()}')
asyncio.run(run('ls /zzz'))
выведет:
['ls /zzz' exited with 1]
[stderr]
ls: /zzz: No such file or directory
Поскольку все функции подпроцессов asyncio являются асинхронными и asyncio предоставляет множество инструментов для работы с такими функциями, легко выполнять и отслеживать несколько подпроцессов параллельно. Действительно, тривиально изменить приведённый выше пример для одновременного выполнения нескольких команд:
async def main():
await asyncio.gather(
run('ls /zzz'),
run('sleep 1; echo "hello"'))
asyncio.run(main())
См. также подраздел Примеры.
Creating SubprocessesСоздание подпроцессов
- async asyncio.create_subprocess_exec(program, *args, stdin=None, stdout=None, stderr=None, limit=None, **kwds)¶
Создать подпроцесс.
Аргумент limit устанавливает ограничение буфера для обёрток
StreamReaderдляstdoutиstderr(еслиsubprocess.PIPEпередаётся аргументам stdout и stderr).Возвращает экземпляр
Process.Смотрите документацию
loop.subprocess_exec()для других параметров.Если объект процесса будет собран сборщиком мусора, когда процесс всё ещё выполняется, дочерний процесс будет уничтожен.
Изменено в версии 3.10: Удалён параметр loop.
- async asyncio.create_subprocess_shell(cmd, stdin=None, stdout=None, stderr=None, limit=None, **kwds)¶
Выполняет команду оболочки cmd.
Аргумент limit устанавливает ограничение буфера для обёрток
StreamReaderдляstdoutиstderr(еслиsubprocess.PIPEпередаётся аргументам stdout и stderr).Возвращает экземпляр
Process.Смотрите документацию
loop.subprocess_shell()для других параметров.Если объект процесса будет собран сборщиком мусора, когда процесс всё ещё выполняется, дочерний процесс будет уничтожен.
Важно
Ответственность приложения заключается в том, чтобы все пробельные и специальные символы были правильно экранированы для предотвращения уязвимостей внедрения команд оболочки. Функция
shlex.quote()может использоваться для правильного экранирования пробельных и специальных символов оболочки в строках, которые будут использоваться для построения команд оболочки.Изменено в версии 3.10: Удалён параметр loop.
Примечание
Подпроцессы доступны в Windows, если используется ProactorEventLoop. См. Поддержка подпроцессов в Windows
для подробностей.
Смотрите также
asyncio также имеет следующие низкоуровневые API для работы с подпроцессами:
loop.subprocess_exec(), loop.subprocess_shell(),
loop.connect_read_pipe(), loop.connect_write_pipe(),
а также Транспорты подпроцессов
и Протоколы подпроцессов.
ConstantsКонстанты
- asyncio.subprocess.PIPE¶
Может быть передан параметрам stdin, stdout или stderr.
Если PIPE передаётся аргументу stdin, то атрибут
Process.stdinбудет указывать на экземплярStreamWriter.Если PIPE передаётся аргументам stdout или stderr, то атрибуты
Process.stdoutиProcess.stderrбудут указывать на экземплярыStreamReader.
- asyncio.subprocess.STDOUT¶
Специальное значение, которое может использоваться как аргумент stderr и указывает, что стандартный поток ошибок должен быть перенаправлен в стандартный вывод.
- asyncio.subprocess.DEVNULL¶
Специальное значение, которое может использоваться как аргумент stdin, stdout или stderr для функций создания процессов. Оно указывает, что специальный файл
os.devnullбудет использоваться для соответствующего потока подпроцесса.
Interacting with SubprocessesВзаимодействие с подпроцессами
Функции create_subprocess_exec() и create_subprocess_shell() возвращают экземпляры класса Process. Process – это высокоуровневая обёртка, которая позволяет взаимодействовать с подпроцессами и отслеживать их завершение.
- class asyncio.subprocess.Process¶
Объект, который оборачивает процессы ОС, созданные функциями
create_subprocess_exec()иcreate_subprocess_shell().Этот класс предназначен для предоставления API, аналогичного классу
subprocess.Popen, но имеются некоторые заметные отличия:в отличие от Popen, экземпляры Process не имеют эквивалента методу
poll();методы
communicate()иwait()не имеют параметра timeout: используйте функциюwait_for();метод
Process.wait()является асинхронным, тогда как методsubprocess.Popen.wait()реализован как блокирующий занятой цикл;параметр universal_newlines не поддерживается.
Этот класс является не потокобезопасным.
См. также раздел Подпроцессы и потоки.
- async wait()¶
Ожидает завершения дочернего процесса.
Устанавливает и возвращает атрибут
returncode.Примечание
Этот метод может привести к взаимоблокировке при использовании
stdout=PIPEилиstderr=PIPE, если дочерний процесс генерирует такой большой объём вывода, что он блокируется в ожидании, пока буфер канала ОС сможет принять больше данных. Используйте методcommunicate()при использовании каналов, чтобы избежать этой ситуации.
- async communicate(input=None)¶
Взаимодействие с процессом:
отправляет данные в stdin (если input не равен
None);закрывает stdin;
читает данные из stdout и stderr, пока не будет достигнут EOF;
ожидает завершения процесса.
Необязательный аргумент input – это данные (объект
bytes), которые будут отправлены дочернему процессу.Возвращает кортеж
(stdout_data, stderr_data).Если при записи input в stdin возникает исключение
BrokenPipeErrorилиConnectionResetError, оно игнорируется. Это происходит, когда процесс завершается до того, как все данные будут записаны в stdin.Если требуется отправить данные в stdin процесса, процесс должен быть создан с
stdin=PIPE. Аналогично, чтобы получить в результирующем кортеже что-либо, отличное отNone, процесс должен быть создан с аргументамиstdout=PIPEи/илиstderr=PIPE.Обратите внимание, что прочитанные данные буферизируются в памяти, поэтому не используйте этот метод, если размер данных велик или неограничен.
Изменено в версии 3.12: stdin также закрывается при
input=None.
- send_signal(signal)¶
Отправляет сигнал signal дочернему процессу.
Примечание
В Windows
SIGTERMявляется псевдонимомterminate(). СигналыCTRL_C_EVENTиCTRL_BREAK_EVENTмогут быть отправлены процессам, запущенным с параметром creationflags, который включаетCREATE_NEW_PROCESS_GROUP.
- terminate()¶
Останавливает дочерний процесс.
В системах POSIX этот метод отправляет
SIGTERMдочернему процессу.В Windows функция Win32 API
TerminateProcess()вызывается для остановки дочернего процесса.
- kill()¶
Завершить дочерний процесс.
В POSIX-системах этот метод отправляет
SIGKILLдочернему процессу.В Windows этот метод является псевдонимом для
terminate().
- stdin¶
Стандартный поток ввода (
StreamWriter) илиNone, если процесс был создан сstdin=None.
- stdout¶
Стандартный поток вывода (
StreamReader) илиNone, если процесс был создан сstdout=None.
- stderr¶
Стандартный поток ошибок (
StreamReader) илиNone, если процесс был создан сstderr=None.
Предупреждение
Используйте метод
communicate()вместоprocess.stdin.write(),await process.stdout.read()илиawait process.stderr.read(). Это позволяет избежать взаимоблокировок из-за приостановки чтения или записи потоков и блокировки дочернего процесса.- pid¶
Идентификационный номер процесса (PID).
Обратите внимание, что для процессов, созданных функцией
create_subprocess_shell(), этот атрибут является PID порождённой оболочки.
- returncode¶
Код возврата процесса при его завершении.
Значение
Noneуказывает на то, что процесс ещё не завершён.Для процессов, созданных с
create_subprocess_exec(), отрицательное значение-Nуказывает, что дочерний процесс был завершён сигналомN(только POSIX).Для процессов, созданных с
create_subprocess_shell(), код возврата отражает статус завершения самой оболочки (например,/bin/sh), который может отображать сигналы в коды, такие как128+N. За подробностями обращайтесь к документации оболочки (например, раздел Exit Status руководства Bash).
Subprocess and ThreadsПодпроцессы и потоки
Стандартный цикл событий asyncio поддерживает запуск подпроцессов из разных потоков по умолчанию.
В Windows подпроцессы поддерживаются только ProactorEventLoop (по умолчанию), SelectorEventLoop не поддерживает подпроцессы.
Обратите внимание, что альтернативные реализации цикла событий могут иметь свои ограничения; обращайтесь к их документации.
Смотрите также
ExamplesПримеры
Пример использования класса Process для управления подпроцессом и класса StreamReader для чтения из его стандартного вывода.
Подпроцесс создаётся функцией create_subprocess_exec():
import asyncio
import sys
async def get_date():
code = 'import datetime as dt; print(dt.datetime.now())'
# Создать подпроцесс; перенаправить стандартный вывод
# в канал.
proc = await asyncio.create_subprocess_exec(
sys.executable, '-c', code,
stdout=asyncio.subprocess.PIPE)
# Прочитать одну строку вывода.
data = await proc.stdout.readline()
line = data.decode('ascii').rstrip()
# Дождаться завершения подпроцесса.
await proc.wait()
return line
date = asyncio.run(get_date())
print(f"Current date: {date}")
См. также тот же пример, написанный с использованием низкоуровневых API.