18.5.6. Подпроцесс
Исходный код: 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), где транспорт является экземпляромBaseSubprocessTransport.Этот метод является корутиной.
Параметры см. в конструкторе класса
subprocess.Popen.
-
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), где транспорт является экземпляром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 должен быть bytes.communicate()возвращает кортеж(stdout_data, stderr_data).Если исключение
BrokenPipeErrorилиConnectionResetErrorвозникает при записи input в stdin, оно игнорируется. Это происходит, когда процесс завершается до записи всех данных в stdin.Чтобы отправлять данные в stdin процесса, необходимо создать объект процесса с
stdin=PIPE. Аналогично, чтобы получить в результирующем кортеже что-то кромеNone, нужно также указатьstdout=PIPEи/илиstderr=PIPE.Этот метод является корутиной.
Примечание
Прочитанные данные буферизируются в памяти, поэтому не используйте этот метод, если размер данных велик или неограничен.
Изменено в версии 3.4.2: Метод теперь игнорирует
BrokenPipeErrorиConnectionResetError.
-
send_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. Подпроцесс с использованием транспорта и протокола
Пример протокола подпроцесса, используемого для получения вывода подпроцесса и\nожидания его завершения. Подпроцесс создаётся методом\nAbstractEventLoop.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)
# Создать подпроцесс, управляемый протоколом DateProtocol,
# перенаправить стандартный вывод в канал
create = loop.subprocess_exec(lambda: DateProtocol(exit_future),
sys.executable, '-c', code,
stdin=None, stderr=None)
transport, protocol = yield from create
# Ожидать завершения подпроцесса с помощью метода process_exited()
# протокола
yield from exit_future
# Закрыть stdout канал
transport.close()
# Прочитать вывод, собранный методом pipe_data_received()
# метод протокола
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 для управления\nподпроцессом и класса StreamReader для чтения из стандартного\nвывода. Подпроцесс создаётся функцией\ncreate_subprocess_exec():
import asyncio.subprocess
import sys
@asyncio.coroutine
def get_date():
code = 'import datetime; print(datetime.datetime.now())'
# Создать подпроцесс, перенаправить стандартный вывод в канал
create = asyncio.create_subprocess_exec(sys.executable, '-c', code,
stdout=asyncio.subprocess.PIPE)
proc = yield from create
# Прочитать одну строку вывода
data = yield from proc.stdout.readline()
line = data.decode('ascii').rstrip()
# Дождаться завершения подпроцесса
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()