Содержание страницы
Подпроцессы¶Subprocesses
Исходный код: Lib/asyncio/subprocess.py, Lib/asyncio/base_subprocess.py
В этом разделе описываются высокоуровневые async/await asyncio API для создания и управления подпроцессами.
Вот пример того, как 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
-
coroutine
asyncio.create_subprocess_exec(program, *args, stdin=None, stdout=None, stderr=None, limit=None, **kwds)¶ Создание подпроцесса.
Аргумент limit устанавливает ограничение буфера для обёрток
StreamReaderдляProcess.stdoutиProcess.stderr(еслиsubprocess.PIPEпередаётся в аргументы stdout и stderr).Возвращает экземпляр
Process.См. документацию
loop.subprocess_exec()для других параметров.Изменено в версии 3.10: Удалён параметр loop.
-
coroutine
asyncio.create_subprocess_shell(cmd, stdin=None, stdout=None, stderr=None, limit=None, **kwds)¶ Выполняет команду оболочки cmd.
Аргумент limit устанавливает ограничение буфера для обёрток
StreamReaderдляProcess.stdoutиProcess.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 не поддерживается.
This class is не является потокобезопасным.
См. также раздел Подпроцессы и потоки .
-
coroutine
wait()¶ Ожидает завершения дочернего процесса.
Устанавливает и возвращает атрибут
returncode.Примечание
Этот метод может привести к взаимоблокировке при использовании
stdout=PIPEилиstderr=PIPE, если дочерний процесс генерирует настолько много вывода, что он блокируется в ожидании, пока буфер системного канала (pipe) примет больше данных. Во избежание этой ситуации используйте методcommunicate()при работе с каналами.
-
coroutine
communicate(input=None)¶ Взаимодействие с процессом:
отправляет данные в stdin (если input не равен
None);читает данные из stdout и stderr до достижения конца файла (EOF);
ожидает завершения процесса.
Необязательный аргумент input – это данные (объект
bytes), которые будут отправлены дочернему процессу.Возвращает кортеж
(stdout_data, stderr_data).Если возникает исключение
BrokenPipeErrorилиConnectionResetErrorпри записи input в stdin, это исключение игнорируется. Такая ситуация возникает, когда процесс завершается до того, как все данные будут записаны в stdin.Если требуется отправить данные в stdin процесса, процесс должен быть создан с
stdin=PIPE. Аналогично, чтобы получить в результирующем кортеже что-то, отличное отNone, процесс должен быть создан с аргументамиstdout=PIPEи/илиstderr=PIPE.Обратите внимание, что прочитанные данные буферизуются в памяти, поэтому не используйте этот метод, если размер данных велик или неограничен.
-
send_signal(signal)¶ Отправляет сигнал signal дочернему процессу.
Примечание
В Windows
SIGTERMявляется псевдонимом дляterminate().CTRL_C_EVENTиCTRL_BREAK_EVENTмогут быть отправлены процессам, запущенным с параметром creationflags, который содержитCREATE_NEW_PROCESS_GROUP.
-
terminate()¶ Останавливает дочерний процесс.
В системах POSIX этот метод отправляет
signal.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).
Подпроцессы и потоки¶Subprocess and Threads
Стандартный цикл событий asyncio поддерживает запуск подпроцессов из разных потоков по умолчанию.
В Windows подпроцессы поддерживаются только ProactorEventLoop (по умолчанию),
SelectorEventLoop не поддерживает подпроцессы.
В UNIX наблюдатели дочерних процессов используются для ожидания завершения подпроцессов, см. Наблюдатели процессов для получения дополнительной информации.
Изменено в версии 3.8: UNIX перешёл на использование ThreadedChildWatcher для запуска подпроцессов из
разных потоков без каких-либо ограничений.
Запуск подпроцесса с неактивным текущим наблюдателем дочерних процессов вызывает
RuntimeError.
Обратите внимание: альтернативные реализации цикла событий могут иметь собственные ограничения; обратитесь к их документации.
См. также
Примеры¶Examples
Пример использования класса Process для
управления подпроцессом и класса StreamReader для чтения
из его стандартного вывода.
Подпроцесс создаётся функцией create_subprocess_exec():
import asyncio
import sys
async def get_date():
code = 'import datetime; print(datetime.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.