Подтвердить что ты не робот

Twisted: создание кода без блокировки

Я немного озадачен тем, как писать асинхронный код в python/twisted. Предположим (для аргументов) я подвергаю функцию миру, который примет число и вернет True/False, если он является простым/неправым, поэтому он выглядит примерно так:


def IsPrime(numberin):
    for n in range(2,numberin):
        if numberin % n == 0: return(False)
    return(True)

(просто для иллюстрации).

Теперь можно сказать, что есть веб-сервер, который должен вызывать IsPrime на основе представленного значения. Это займет много времени для больших numberin.

Если в то же время другой пользователь запрашивает простоту небольшого числа, существует ли способ запуска двух вызовов функций асинхронно с использованием архитектуры реактора/отсрочки, чтобы результат короткого вычитания возвращался до результата длинный calc?

Я понимаю, как это сделать, если функциональность IsPrime поступает с какого-то другого веб-сервера, на который мой веб-сервер будет делать отложенный getPage, но что, если это просто локальная функция?

т.е. может ли Twisted как-то разделить время между двумя вызовами на IsPrime или потребовать явного вызова нового потока?

Или, должен ли цикл IsPrime быть помещен в серию меньших петель, чтобы можно было быстро вернуть управление в реактор?

Или что-то еще?

4b9b3361

Ответ 1

Я думаю, что ваше нынешнее понимание в основном правильное. Twisted - это просто библиотека Python, и написанный вами код Python, который вы пишете для его использования, выполняется нормально, как вы ожидаете, код Python: если у вас есть только один поток (и один процесс), тогда происходит только одна вещь. Почти ни один API, предоставляемый Twisted, не создает новые потоки или процессы, поэтому в нормальном ходу вещей ваш код работает последовательно; isPrime не может выполнить второй раз, пока он не завершит выполнение в первый раз.

По-прежнему рассматривая только один поток (и один процесс), все "concurrency" или "parallelism" Twisted происходят из-за того, что вместо блокировки сетевого ввода-вывода (и некоторых других блокировок операций), Twisted предоставляет инструменты для выполнения операции неблокирующим способом. Это позволяет вашей программе продолжать выполнять другую работу, если она в противном случае могла бы застрять, ничего не делая, ожидая завершения операции блокировки ввода-вывода (например, чтения или записи в сокет).

Можно сделать вещи "асинхронными", разделив их на маленькие куски и разрешив обработчикам событий между этими кусками. Иногда это полезный подход, если преобразование не делает код слишком сложным для понимания и поддержки. Twisted предоставляет помощника для планирования этих кусков работы, cooperate. Полезно использовать этот помощник, поскольку он может принимать решения о планировании на основе всех разных источников работы и гарантировать, что есть время, оставшееся для обслуживания источников событий без значительных дополнительных латентностей (другими словами, чем больше заданий вы добавляете к нему, тем меньше времени будет у каждой работы, так что реактор может продолжать выполнять свою работу).

Twisted также предоставляет несколько API для обработки потоков и процессов. Они могут быть полезны, если не очевидно, как разбить работу на куски. Вы можете использовать deferToThread для запуска (потокобезопасной!) Функции в пуле потоков. Удобно, что этот API возвращает Deferred, который, в конце концов, запускает возвращаемое значение функции (или с помощью Failure, если функция вызывает исключение). Эти Отсрочки выглядят как любой другой, и что касается использующего их кода, он может так же возвращаться от вызова, как getPage - функция, которая не использует никаких дополнительных потоков, просто неблокирующих операций ввода-вывода и обработчиков событий.

Поскольку Python не идеально подходит для запуска нескольких потоков, связанных с процессором, в одном процессе, Twisted также предоставляет неблокирующий API для запуска и передачи сообщений с дочерними процессами. Вы можете отключить вычисления для таких процессов, чтобы использовать преимущества дополнительных процессоров или ядер, не беспокоясь о том, что GIL замедляет вас, что не предлагает ни стратегия разделения, ни поток. API-интерфейс самого низкого уровня для работы с такими процессами - reactor.spawnProcess. Существует также Ampoule, пакет, который будет управлять пулом процессов для вас и предоставляет аналог deferToThread для процессов, deferToAMPProcess.