Потоки¶
Исходный код: 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())
См. также подраздел Примеры.
Создание подпроцессов¶
-
coroutine
asyncio.
create_subprocess_exec
(program, *args, stdin=None, stdout=None, stderr=None, loop=None, limit=None, **kwds)¶ Создать подпроцессы.
Аргумент limit устанавливает предел буфера для
StreamReader
оболочек дляProcess.stdout
иProcess.stderr
(еслиsubprocess.PIPE
передается аргументам stdout и stderr).Возвращает
Process
сущность.Другие параметры см. в документации
loop.subprocess_exec()
.Deprecated since version 3.8, will be removed in version 3.10: Параметр loop.
-
coroutine
asyncio.
create_subprocess_shell
(cmd, stdin=None, stdout=None, stderr=None, loop=None, limit=None, **kwds)¶ Выполните команду cmd оболочки.
Аргумент limit устанавливает предел буфера для
StreamReader
оболочек дляProcess.stdout
иProcess.stderr
(еслиsubprocess.PIPE
передается аргументам stdout и stderr).Возвращает
Process
сущность.Другие параметры см. в документации
loop.subprocess_shell()
.Важно
Приложение несет ответственность за то, чтобы все пробелы и специальные символы цитировались надлежащим образом, чтобы избежать шелл инъекцию уязвимостей. Функция
shlex.quote()
может быть используемый для правильного выхода из пробелов и специальных символов оболочки в строки, которые будут используемый для создания команд оболочки.Deprecated since version 3.8, will be removed in version 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.
Если 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
будет используемый для соответствующего потока подпроцессы.
Взаимодействие с подпроцессами¶
И 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 не поддерживается.
Класс не потокобезопасно.
См. также раздел Подпроцессы и потоки.
-
coroutine
wait
()¶ Дождитесь завершения дочернего процесса.
Установить возвращает атрибут
returncode
.Примечание
Этот метод может взаимоблокироваться при использовании
stdout=PIPE
илиstderr=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
аргументами.Следует отметить, что считанные данные буферизуются в памяти, поэтому не используйте эту метод, если размер данных большой или неограниченный.
- Послать данные в stdin (если input не является
-
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()
orawait 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())'
# Создание подпроцесса и перенаправление стандартный вывод
# в пайп.
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.