Подпроцессы
Исходный код: 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())
См. также подраздел Примеры.
Создание подпроцессов
-
async asyncio.create_subprocess_exec(program, *args, stdin=None, stdout=None, stderr=None, limit=None, **kwds) -
Создаёт подпроцесс.
Аргумент limit задаёт предел буфера для оболочек
StreamReaderдляstdoutиstderr(если аргументам stdout и stderr переданоsubprocess.PIPE).Возвращает экземпляр
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(если аргументам stdout и stderr переданоsubprocess.PIPE).Возвращает экземпляр
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(), а также транспорты подпроцессов и протоколы подпроцессов.
Константы
-
asyncio.subprocess.PIPE -
Может быть передана параметрам stdin, stdout или stderr.
Если аргументу stdin передано PIPE, атрибут
Process.stdinбудет указывать на экземплярStreamWriter.Если аргументам stdout или stderr передано PIPE, атрибуты
Process.stdoutиProcess.stderrбудут указывать на экземплярыStreamReader.
-
asyncio.subprocess.STDOUT -
Специальное значение, которое можно использовать в качестве аргумента stderr; оно указывает, что стандартный поток ошибок следует перенаправить в стандартный поток вывода.
-
asyncio.subprocess.DEVNULL -
Специальное значение, которое можно использовать в качестве аргумента stdin, stdout или stderr функций создания процессов. Оно указывает, что для соответствующего потока подпроцесса будет использоваться специальный файл
os.devnull.
Взаимодействие с подпроцессами
Функции create_subprocess_exec() и create_subprocess_shell() возвращают экземпляры класса Process. Process — это высокоуровневая оболочка, которая позволяет взаимодействовать с подпроцессами и отслеживать их завершение.
-
class asyncio.subprocess.Process -
Объект-оболочка для процессов ОС, созданных функциями
create_subprocess_exec()иcreate_subprocess_shell().Этот класс имеет API, похожий на 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. - отправляет данные в stdin (если input не равен
-
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означает, что процесс ещё не завершился.Отрицательное значение
-Nозначает, что дочерний процесс был завершён сигналомN(только POSIX).
- в отличие от Popen, у экземпляров Process нет аналога метода
Подпроцессы и потоки
Стандартный цикл событий asyncio по умолчанию поддерживает запуск подпроцессов из разных потоков.
В Windows подпроцессы поддерживаются только в ProactorEventLoop (используется по умолчанию); SelectorEventLoop не поддерживает подпроцессы.
В UNIX для ожидания завершения подпроцессов используются наблюдатели дочерних процессов. Подробнее см. в разделе Наблюдатели процессов.
Изменено в версии 3.8: В UNIX для запуска подпроцессов из разных потоков без каких-либо ограничений теперь используется ThreadedChildWatcher.
Попытка запустить подпроцесс при неактивном текущем наблюдателе дочерних процессов вызывает исключение RuntimeError.
Обратите внимание, что альтернативные реализации циклов событий могут иметь собственные ограничения; см. их документацию.
См. также
Примеры
Пример использования класса Process для управления подпроцессом и класса StreamReader для чтения из его стандартного потока вывода.
Подпроцесс создаётся функцией create_subprocess_exec():
import asyncio
import sys
async def get_date():
code = 'import datetime; print(datetime.datetime.now())'
# Create the subprocess; redirect the standard output
# into a pipe.
proc = await asyncio.create_subprocess_exec(
sys.executable, '-c', code,
stdout=asyncio.subprocess.PIPE)
# Read one line of output.
data = await proc.stdout.readline()
line = data.decode('ascii').rstrip()
# Wait for the subprocess exit.
await proc.wait()
return line
date = asyncio.run(get_date())
print(f"Current date: {date}")
См. также тот же пример, написанный с использованием низкоуровневых API.
© 2001–2025 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.13/library/asyncio-subprocess.html