Подпроцессы
Исходный код: Lib/asyncio/subprocess.py
18.5.6.1. Цикл обработки событий Windows
В Windows по умолчанию используется цикл обработки событий SelectorEventLoop, который не поддерживает подпроцессы. Вместо него следует использовать ProactorEventLoop. Пример использования в Windows:
import asyncio, sys
if sys.platform == 'win32':
loop = asyncio.ProactorEventLoop()
asyncio.set_event_loop(loop)
См. также
18.5.6.2. Создание подпроцесса: API высокого уровня с использованием Process
-
coroutine asyncio.create_subprocess_exec(*args, stdin=None, stdout=None, stderr=None, loop=None, limit=None, **kwds) -
Создаёт подпроцесс.
Параметр limit задаёт предел буфера, передаваемый в
StreamReader. Другие параметры см. вAbstractEventLoop.subprocess_exec().Возвращает экземпляр
Process.Эта функция является корутиной.
-
coroutine asyncio.create_subprocess_shell(cmd, stdin=None, stdout=None, stderr=None, loop=None, limit=None, **kwds) -
Выполняет командную строку cmd.
Параметр limit задаёт предел буфера, передаваемый в
StreamReader. Другие параметры см. вAbstractEventLoop.subprocess_shell().Возвращает экземпляр
Process.Приложения несут ответственность за правильное экранирование пробелов и метасимволов в командных строках, чтобы избежать уязвимостей типа «всплеск оболочки». Функцию
shlex.quote()можно использовать для правильного экранирования пробелов и метасимволов оболочки в строках, которые будут использоваться для построения команд оболочки.Эта функция является корутиной.
Используйте методы AbstractEventLoop.connect_read_pipe() и AbstractEventLoop.connect_write_pipe() для подключения каналов.
18.5.6.3. Создание подпроцесса: API низкого уровня с использованием subprocess.Popen
Асинхронное выполнение подпроцессов с использованием модуля subprocess.
-
coroutine AbstractEventLoop.subprocess_exec(protocol_factory, *args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs) -
Создаёт подпроцесс из одной или нескольких строковых аргументов (строки или байтовые строки, закодированные в кодировку файловой системы), где первая строка указывает программу для выполнения, а остальные строки — аргументы программы. (Таким образом, вместе аргументы строк образуют значение
sys.argvпрограммы, предполагая, что это скрипт Python.) Это аналогично стандартному библиотечному классуsubprocess.Popen, вызываемому с параметром shell=False и списком строк, переданных в качестве первого аргумента; однако, гдеPopenпринимает один аргумент, который является списком строк,subprocess_exec()принимает несколько строковых аргументов.protocol_factory должен создавать подкласс класса
asyncio.SubprocessProtocol.Другие параметры:
-
stdin: либо объект, подобный файлу, представляющий канал, подключаемый к стандартному вводу подпроцесса с помощью
connect_write_pipe(), либо константаsubprocess.PIPE(по умолчанию). По умолчанию создаётся и подключается новый канал. -
stdout: либо объект, подобный файлу, представляющий канал, подключаемый к стандартному выводу подпроцесса с помощью
connect_read_pipe(), либо константаsubprocess.PIPE(по умолчанию). По умолчанию создаётся и подключается новый канал. -
stderr: либо объект, подобный файлу, представляющий канал, подключаемый к стандартному ошибочному выводу подпроцесса с помощью
connect_read_pipe(), либо константаsubprocess.PIPE(по умолчанию) илиsubprocess.STDOUT. По умолчанию создаётся и подключается новый канал. Когда заданоsubprocess.STDOUT, стандартный вывод ошибок подпроцесса подключается к тому же каналу, что и стандартный вывод. - Все остальные ключевые аргументы передаются в
subprocess.Popenбез интерпретации, за исключением bufsize, universal_newlines и shell, которые вообще не следует указывать.
Возвращает пару
(transport, protocol), где transport — экземплярBaseSubprocessTransport.Этот метод является корутиной.
См. конструктор класса
subprocess.Popenдля параметров. -
stdin: либо объект, подобный файлу, представляющий канал, подключаемый к стандартному вводу подпроцесса с помощью
-
coroutine AbstractEventLoop.subprocess_shell(protocol_factory, cmd, *, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs) -
Создаёт подпроцесс из cmd, которое является строкой или байтовой строкой, закодированной в кодировку файловой системы, с использованием синтаксиса «оболочки» платформы. Это аналогично стандартному библиотечному классу
subprocess.Popen, вызываемому с параметромshell=True.protocol_factory должен создавать подкласс класса
asyncio.SubprocessProtocol.См.
subprocess_exec()для получения дополнительной информации об оставшихся аргументах.Возвращает пару
(transport, protocol), где transport — экземплярBaseSubprocessTransport.Приложения несут ответственность за правильное экранирование пробелов и метасимволов в командных строках, чтобы избежать уязвимостей типа «всплеск оболочки». Функцию
shlex.quote()можно использовать для правильного экранирования пробелов и метасимволов оболочки в строках, которые будут использоваться для построения команд оболочки.Этот метод является корутиной.
См. также
Методы AbstractEventLoop.connect_read_pipe() и AbstractEventLoop.connect_write_pipe().
18.5.6.4. Константы
-
asyncio.subprocess.PIPE -
Специальное значение, которое может использоваться в качестве аргумента stdin, stdout или stderr для
create_subprocess_shell()иcreate_subprocess_exec()и указывает на то, что должен быть открыт канал к стандартному потоку.
-
asyncio.subprocess.STDOUT -
Специальное значение, которое можно использовать в качестве аргумента stderr для
create_subprocess_shell()иcreate_subprocess_exec()и указывает, что стандартная ошибка должна попадать в тот же обработчик, что и стандартный вывод.
-
asyncio.subprocess.DEVNULL -
Специальное значение, которое может быть использовано в качестве аргумента stdin, stdout или stderr для
create_subprocess_shell()иcreate_subprocess_exec()и указывает, что будет использован специальный файлos.devnull.
18.5.6.5. Процесс
-
class asyncio.subprocess.Process -
Подпроцесс, созданный функцией
create_subprocess_exec()илиcreate_subprocess_shell().API класса
Processразработан так, чтобы быть похожим на API классаsubprocess.Popen, но есть некоторые различия:- Нет явного метода
poll() - Методы
communicate()иwait()не принимают параметр timeout: используйте функциюwait_for() - Параметр universal_newlines не поддерживается (поддерживаются только байтовые строки)
- Метод
wait()классаProcessявляется асинхронным, в то время как методwait()классаPopenреализован как цикл с ожиданием.
Этот класс не потокобезопасен. Смотрите также раздел Подпроцессы и потоки.
-
coroutine wait() -
Ожидает завершения дочернего процесса. Устанавливает и возвращает атрибут
returncode.Этот метод является генератором.
Примечание
Это приведет к тупику при использовании
stdout=PIPEилиstderr=PIPEи дочерний процесс генерирует достаточно вывода в канал, так что он блокируется, ожидая, пока буфер канала ОС примет больше данных. Используйте методcommunicate()при использовании каналов, чтобы избежать этого.
-
coroutine communicate(input=None) -
Взаимодействие с процессом: Отправка данных в stdin. Чтение данных из stdout и stderr до тех пор, пока не будет достигнут конец файла. Ожидание завершения процесса. Необязательный аргумент input должен содержать данные, которые будут отправлены дочернему процессу, или
None, если данные не должны отправляться. Тип input должен быть байтовым.Метод
communicate()возвращает кортеж(stdout_data, stderr_data).Если при записи input в stdin возникает исключение
BrokenPipeErrorилиConnectionResetError, оно игнорируется. Это происходит, когда процесс завершается до того, как все данные будут записаны в stdin.Обратите внимание, что если вы хотите отправлять данные в stdin процесса, вам нужно создать объект Process с
stdin=PIPE. Аналогично, чтобы получить что-либо, кромеNoneв кортеже результата, вам также нужно указатьstdout=PIPEи/илиstderr=PIPE.Этот метод является генератором.
Примечание
Считанные данные буферизуются в памяти, поэтому не используйте этот метод, если размер данных большой или неограничен.
Изменено в версии 3.4.2: Метод теперь игнорирует
BrokenPipeErrorиConnectionResetError.
-
send_signal(signal) -
Отправляет сигнал signal дочернему процессу.
Примечание
В Windows
SIGTERMявляется псевдонимом дляterminate().CTRL_C_EVENTиCTRL_BREAK_EVENTмогут быть отправлены процессам, запущенным с параметром creationflags, который включаетCREATE_NEW_PROCESS_GROUP.
-
terminate() -
Останавливает дочерний процесс. В системах POSIX метод отправляет
signal.SIGTERMдочернему процессу. В Windows вызывается функция Win32 APITerminateProcess()для остановки дочернего процесса.
-
kill() -
Уничтожает дочерний процесс. В системах POSIX функция отправляет
SIGKILLдочернему процессу. В Windowskill()является псевдонимом дляterminate().
-
stdin -
Поток стандартного ввода (
StreamWriter),Noneесли процесс был создан сstdin=None.
-
stdout -
Поток стандартного вывода (
StreamReader),Noneесли процесс был создан сstdout=None.
-
stderr -
Поток стандартной ошибки (
StreamReader),Noneесли процесс был создан сstderr=None.
Предупреждение
Используйте метод
communicate()вместо.stdin.write,.stdout.readили.stderr.readдля предотвращения тупиков из-за приостановки чтения или записи потоков, блокирующих дочерний процесс.-
pid -
Идентификатор процесса.
Обратите внимание, что для процессов, созданных функцией
create_subprocess_shell(), этот атрибут — идентификатор процесса созданного оболочки.
-
returncode -
Код возврата процесса при завершении. Значение
Noneуказывает, что процесс еще не завершен.Отрицательное значение
-Nуказывает, что дочерний процесс был завершен сигналомN(только Unix).
- Нет явного метода
18.5.6.6. Подпроцессы и потоки
asyncio поддерживает запуск подпроцессов из разных потоков, но есть ограничения:
- Цикл событий должен работать в главном потоке
- Наблюдатель за дочерними процессами должен быть инициализирован в главном потоке, до запуска подпроцессов из других потоков. Вызовите функцию
get_child_watcher()в главном потоке для инициализации наблюдателя за дочерними процессами.
Класс asyncio.subprocess.Process не потокобезопасен.
См. также
18.5.6.7. Примеры использования подпроцессов
18.5.6.7.1. Подпроцесс с использованием транспорта и протокола
Пример протокола подпроцесса, используемого для получения вывода подпроцесса и ожидания завершения работы подпроцесса. Подпроцесс создается методом AbstractEventLoop.subprocess_exec():
import asyncio
import sys
class DateProtocol(asyncio.SubprocessProtocol):
def __init__(self, exit_future):
self.exit_future = exit_future
self.output = bytearray()
def pipe_data_received(self, fd, data):
self.output.extend(data)
def process_exited(self):
self.exit_future.set_result(True)
@asyncio.coroutine
def get_date(loop):
code = 'import datetime; print(datetime.datetime.now())'
exit_future = asyncio.Future(loop=loop)
# Create the subprocess controlled by the protocol DateProtocol,
# redirect the standard output into a pipe
create = loop.subprocess_exec(lambda: DateProtocol(exit_future),
sys.executable, '-c', code,
stdin=None, stderr=None)
transport, protocol = yield from create
# Wait for the subprocess exit using the process_exited() method
# of the protocol
yield from exit_future
# Close the stdout pipe
transport.close()
# Read the output which was collected by the pipe_data_received()
# method of the protocol
data = bytes(protocol.output)
return data.decode('ascii').rstrip()
if sys.platform == "win32":
loop = asyncio.ProactorEventLoop()
asyncio.set_event_loop(loop)
else:
loop = asyncio.get_event_loop()
date = loop.run_until_complete(get_date(loop))
print("Current date: %s" % date)
loop.close()
18.5.6.7.2. Подпроцесс с использованием потоков
Пример использования класса Process для управления подпроцессом и класса StreamReader для чтения со стандартного вывода. Подпроцесс создается функцией create_subprocess_exec():
import asyncio.subprocess
import sys
@asyncio.coroutine
def get_date():
code = 'import datetime; print(datetime.datetime.now())'
# Create the subprocess, redirect the standard output into a pipe
create = asyncio.create_subprocess_exec(sys.executable, '-c', code,
stdout=asyncio.subprocess.PIPE)
proc = yield from create
# Read one line of output
data = yield from proc.stdout.readline()
line = data.decode('ascii').rstrip()
# Wait for the subprocess exit
yield from proc.wait()
return line
if sys.platform == "win32":
loop = asyncio.ProactorEventLoop()
asyncio.set_event_loop(loop)
else:
loop = asyncio.get_event_loop()
date = loop.run_until_complete(get_date())
print("Current date: %s" % date)
loop.close()
© 2001–2020 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.6/library/asyncio-subprocess.html