Spec-Zone.ru › Python 3.5

Подпроцессы

1. Цикл событий Windows

В Windows по умолчанию используется цикл событий SelectorEventLoop, который не поддерживает подпроцессы. Вместо него следует использовать ProactorEventLoop. Пример использования в Windows:

import asyncio, sys

if sys.platform == 'win32':
    loop = asyncio.ProactorEventLoop()
    asyncio.set_event_loop(loop)

См. также

Доступные циклы событий и Поддержка платформ.

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.

Приложению необходимо убедиться, что все пробелы и метасимволы корректно заключены в кавычки, чтобы избежать уязвимостей shell injection. Функция shlex.quote() может использоваться для правильного экранирования пробелов и метасимволов оболочки в строках, используемых для построения команд оболочки.

Эта функция является корутинной.

Для подключения каналов используйте методы AbstractEventLoop.connect_read_pipe() и AbstractEventLoop.connect_write_pipe().

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 для параметров.

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.

Приложению необходимо убедиться, что все пробелы и метасимволы корректно заключены в кавычки, чтобы избежать уязвимостей shell injection. Функция shlex.quote() может использоваться для правильного экранирования пробелов и метасимволов оболочки в строках, используемых для построения команд оболочки.

Этот метод является корутинной.

См. также

Методы AbstractEventLoop.connect_read_pipe() и AbstractEventLoop.connect_write_pipe().

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.

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)

Взаимодействие с процессом: Отправка данных в стандартный ввод. Чтение данных из стандартного вывода и стандартной ошибки до достижения конца файла. Ожидание завершения процесса. Дополнительный аргумент input должен содержать данные для отправки дочернему процессу, или None, если данные не должны отправляться. Тип input должен быть байтовым.

Метод communicate() возвращает кортеж (stdout_data, stderr_data).

Если при записи input в стандартный ввод возникает исключение BrokenPipeError или ConnectionResetError, исключение игнорируется. Это происходит, когда процесс завершается до того, как все данные будут записаны в стандартный ввод.

Обратите внимание, что если вы хотите отправить данные в стандартный ввод процесса, вам нужно создать объект 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 API TerminateProcess() для остановки дочернего процесса.

kill()

Убить дочерний процесс. В операционных системах Posix функция отправляет SIGKILL дочернему процессу. В Windows kill() является псевдонимом для 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).

6. Подпроцессы и потоки

asyncio поддерживает запуск подпроцессов из разных потоков, но есть ограничения:

  • Цикл событий должен выполняться в главном потоке
  • Наблюдатель дочернего процесса должен быть создан в главном потоке, до выполнения дочерних процессов из других потоков. Вызовите функцию get_child_watcher() в главном потоке для создания наблюдателя дочернего процесса.

Класс asyncio.subprocess.Process не является потокобезопасным.

См. также

Раздел Конкурентность и многопоточность в asyncio.

7. Примеры дочерних процессов

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()

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.5/library/asyncio-subprocess.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API