Методы цикла событий, описанные в этом подразделе, относятся к низкоуровневому API. В обычном коде async/await рассмотрите возможность использования вместо них вспомогательных функций высокого уровня asyncio.create_subprocess_shell()
и asyncio.create_subprocess_exec()
.
Примечание. В Windows реализация цикла событий asyncio
ProactorEventLoop
(по умолчанию) поддерживает подпроцессы, а реализация SelectorEventLoop
- нет.
Также в Windows не поддерживается функция политики абстрактного цикла policy.set_child_watcher()
(устарело с Python 3.12.), поскольку реализация ProactorEventLoop
имеет другой механизм наблюдения за дочерними процессами.
Прежде чем что-то делать с циклом событий, его необходимо создать или получить функциями, описанными в разделе "Создание, запуск и получение цикла событий".
loop.subprocess_exec()
создает subprocess.Popen
с аргументом shell=False
,loop.subprocess_shell()
создает subprocess.Popen
с аргументом shell=True
.loop.connect_read_pipe()
регистрирует канал для чтения,loop.connect_write_pipe()
регистрирует канал для записи,asyncio.SubprocessTransport
,asyncio.SubprocessProtocol
,loop.subprocess_exec(protocol_factory, *args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)
:Метод loop.subprocess_exec()
создает подпроцесс из одного или нескольких строковых аргументов, указанных в args
и представляет собой сопрограмму.
Аргумент args
должен быть списком строк, представленных как str
или bytes
, закодированные в кодировке файловой системы.
Первая строка указывает исполняемый файл программы, а остальные строки указывают аргументы. Вместе строковые аргументы образуют sys.argv
программы.
Метод loop.subprocess_exec()
похож на класс стандартной библиотеки subprocess.Popen
, вызываемый с аргументом shell=False
и списком строк, переданных в качестве первого аргумента. Если Popen
принимает единственный аргумент, который представляет собой список строк, то метод loop.subprocess_exec()
принимает несколько строковых аргументов.
Аргумент protocol_factory
должен быть вызываемым объектом, возвращающим подкласс класса asyncio.SubprocessProtocol
.
Остальные аргументы:
stdin
может быть любым из следующих:
loop.connect_write_pipe()
;subprocess.PIPE
, которая создаст новый канал и подключит его;None
, которое заставит подпроцесс наследовать дескриптор файла от этого процесса;subprocess.DEVNULL
, которая указывает, что будет использоваться специальный файл os.devnull
.stdout
может быть любым из следующих:
loop.connect_write_pipe()
;subprocess.PIPE
, которая создаст новый канал и подключит его;None
, которое заставит подпроцесс наследовать дескриптор файла от этого процесса;subprocess.DEVNULL
, которая указывает, что будет использоваться специальный файл os.devnull
.stderr
может быть любым из следующих:
loop.connect_write_pipe()
;subprocess.PIPE
, которая создаст новый канал и подключит его;None
, которое заставит подпроцесс наследовать дескриптор файла от этого процесса;subprocess.DEVNULL
, которая указывает, что будет использоваться специальный файл os.devnull
.subprocess.STDOUT
, которая подключит стандартный поток ошибок к стандартному потоку вывода процесса.Все остальные ключевые аргументы передаются в subprocess.Popen()
без интерпретации, за исключением bufsize
, universal_newlines
, shell
, text
, encoding
и errors
, которые вообще не должны указываться.
API подпроцесса модуля asyncio
не поддерживает декодирование потоков как текста. Для преобразования байтов, возвращаемых из потока, в текст может использоваться функция bytes.decode()
.
Возвращает пару (transport, protocol), где транспорт соответствует базовому классу asyncio.SubprocessTransport
, а протокол - объект, экземпляр которого был создан с помощью аргумента protocol_factory
.
loop.subprocess_shell(protocol_factory, cmd, *, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)
:Метод loop.subprocess_shell()
создает подпроцесс из cmd
, который может быть строкой str
или строкой bytes
, закодированной в кодировке файловой системы, с использованием синтаксиса терминала платформы.
Представляет собой сопрограмму.
Метод loop.subprocess_shell()
похож на класс subprocess.Popen
стандартной библиотеки, вызываемый с аргументом shell=True
.
Аргумент protocol_factory
должен быть вызываемым объектом, возвращающим подкласс класса asyncio.SubprocessProtocol
.
Для получения информации об остальных аргументах, смотрите метод цикла событий loop.subprocess_exec()
.
Возвращает пару (transport, protocol), где транспорт соответствует базовому классу asyncio.SubprocessTransport
, а протокол - объект, экземпляр которого был создан с помощью аргумента protocol_factory
.
Примечание. Приложение несет ответственность за то, чтобы все пробелы и специальные символы были указаны в кавычках, во избежании уязвимостей. Можно использовать функцию shlex.quote()
для правильного экранирования пробелов и специальных символов в строках, которые будут использоваться для создания команд оболочки.
В реализации цикла событий SelectorEventLoop
канал устанавливается в неблокирующий режим.
Примечание. реализация SelectorEventLoop
не поддерживает указанные ниже методы в Windows. Для Windows используйте реализацию ProactorEventLoop
.
Смотрите также методы loop.subprocess_exec()
и loop.subprocess_shell()
.
loop.connect_read_pipe()
регистрирует канал для чтения,loop.connect_write_pipe()
регистрирует канал для записи.loop.connect_read_pipe(protocol_factory, pipe)
:Метод loop.connect_read_pipe()
регистрирует один конец канала для чтения в цикле событий. Представляет собой сопрограмму.
protocol_factory
должен быть вызываемым объектом, возвращающим реализацию протокола asyncio
.pipe
- это файлоподобный объект.Возвращает пару (transport, protocol)
, где транспорт transport
поддерживает интерфейс ReadTransport
, а протокол protocol
- это объект, созданный с помощью объекта protocol_factory
.
В реализации цикла событий SelectorEventLoop
канал устанавливается в неблокирующий режим.
loop.connect_write_pipe(protocol_factory, pipe)
:Метод loop.connect_write_pipe()
регистрирует другой конец канала для записи в цикле событий. Представляет собой сопрограмму.
protocol_factory
должен быть вызываемым объектом, возвращающим реализацию протокола asyncio
.pipe
- это файлоподобный объект.Возвращает пару (transport, protocol)
, где транспорт transport
поддерживает интерфейс WriteTransport
, а протокол protocol
- это объект, созданный с помощью объекта protocol_factory
.
asyncio.SubprocessTransport(BaseProtocol)
:Класс asyncio.SubprocessTransport(BaseProtocol)
представляет собой абстракцию, которая осуществляет связь между родительским и дочерним процессами ОС.
Экземпляры класса SubprocessTransport
возвращаются из методов цикла событий loop.subprocess_shell()
и loop.subprocess_exec()
.
Методы транспорта субпроцесса:
SubprocessTransport.get_pid()
возвращает PID подпроцесса,SubprocessTransport.get_pipe_transport()
возвращает транспорт для канала,SubprocessTransport.get_returncode()
возвращает код возврата подпроцесса,SubprocessTransport.kill()
убивает подпроцесс,SubprocessTransport.send_signal()
отправляет сигнал подпроцесс,SubprocessTransport.terminate()
останавливает подпроцесс,SubprocessTransport.close()
завершает подпроцесс.SubprocessTransport.get_pid()
:Метод SubprocessTransport.get_pid()
возвращает идентификатор подпроцесса PID как целое число.
SubprocessTransport.get_pipe_transport(fd)
:Метод SubprocessTransport.get_pipe_transport()
возвращает транспорт для канала связи, соответствующий целочисленному файловому дескриптору fd
:
stdin
или если подпроцесс был создан без stdin=PIPE
- то None
;stdout
или если подпроцесс был создан без stdout=PIPE
- то None
;stderr
или если подпроцесс был создан без stderr=PIPE
- то None
;fd
: None
.SubprocessTransport.get_returncode()
:Метод SubprocessTransport.get_returncode()
возвращает код возврата подпроцесса в виде целого числа или если он не был возвращен - то None
.
Метод похож на атрибут subprocess.Popen.returncode
]subprocess.Popen.obj.
SubprocessTransport.kill()
:Метод SubprocessTransport.kill()
убивает подпроцесс.
В системах POSIX функция отправляет SIGKILL
подпроцессу. В Windows этот метод является псевдонимом для метода .terminate()
.
Смотрите также описание метода subprocess.Popen.kill()
.
SubprocessTransport.send_signal(signal)
:Метод SubprocessTransport.send_signal()
отправляет номер сигнала в подпроцесс, как это делает subprocess.Popen.send_signal()
.
SubprocessTransport.terminate()
:Метод SubprocessTransport.terminate()
останавливает подпроцесс.
В системах POSIX этот метод отправляет SIGTERM
в подпроцесс. В Windows, для остановки подпроцесса вызывается функция Windows API TerminateProcess()
.
Смотрите также описание метода subprocess.Popen.terminate().
SubprocessTransport.close()
:Метод SubprocessTransport.close()
завершает подпроцесс, вызвав метод SubprocessTransport.kill().
Метод так же закрывает транспорты каналов stdin
, stdout
и stderr
.
asyncio.SubprocessProtocol(BaseProtocol)
:Класс asyncio.SubprocessProtocol(BaseProtocol)
представляет собой базовый класс для реализации протоколов, взаимодействующих с дочерними процессами (однонаправленные каналы).
Экземпляры протокола дейтаграмм должны создаваться фабриками протоколов, переданными в методы цикла событий loop.subprocess_shell()
и loop.subprocess_exec()
.
Методы протокола субпроцесса:
SubprocessProtocol.pipe_data_received()
вызывается, когда дочерний процесс записывает данные,SubprocessProtocol.pipe_connection_lost()
вызывается, когда один из каналов закрывается,SubprocessProtocol.process_exited()
вызывается, когда дочерний процесс выполнился.SubprocessProtocol.pipe_data_received(fd, data)
:Метод SubprocessProtocol.pipe_data_received()
вызывается, когда дочерний процесс записывает данные в свой stdout
или stderr
канала.
fd
- это целочисленный файловый дескриптор канала.data
- это непустой байтовый объект, содержащий полученные данные.SubprocessProtocol.pipe_connection_lost(fd, exc)
:Метод SubprocessProtocol.pipe_connection_lost()
вызывается, когда один из каналов, взаимодействующих с дочерним процессом, закрывается.
Аргумент fd
- это целочисленный файловый дескриптор, который был закрыт.
SubprocessProtocol.process_exited()
:Метод SubprocessProtocol.process_exited()
вызывается, когда дочерний процесс выполнился.
Пример протокола подпроцесса, используемого для получения выходных данных подпроцесса и ожидания выхода подпроцесса.
Подпроцесс создается методом цикла событий loop.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) async def get_date(): # Получаем ссылку на цикл событий, т.к. # планируем использовать низкоуровневый API. loop = asyncio.get_running_loop() code = 'import datetime; print(datetime.datetime.now())' exit_future = asyncio.Future(loop=loop) # Создаем подпроцесс, управляемый 'DateProtocol'; # перенаправим стандартный вывод в pipe. transport, protocol = await loop.subprocess_exec( lambda: DateProtocol(exit_future), sys.executable, '-c', code, stdin=None, stderr=None) # Ждем выхода подпроцесса, используя # метод 'DateProtocol.process_exited()' . await exit_future # Закроем стандартный вывод. transport.close() # Читаем выходные данные, собранные # методом `DateProtocol.pipe_data_received()`. data = bytes(protocol.output) return data.decode('ascii').rstrip() date = asyncio.run(get_date()) print(f"Current date: {date}")