Потоки¶
Исходный код: 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.
