Я работаю над библиотекой Python, которая взаимодействует с API веб-службы. Как и многие другие веб-службы, с которыми я сталкивался, этот запрашивает ограничение скорости запросов. Я хотел бы предоставить необязательный параметр limit для создания экземпляра класса, который, если он предоставлен, будет удерживать исходящие запросы до тех пор, пока не пройдет указанное количество секунд.
Я понимаю, что общий сценарий таков: экземпляр класса делает запрос через метод. Когда это происходит, метод излучает некоторый сигнал, который устанавливает где-то переменную блокировки, и запускает таймер обратного отсчета для количества секунд в limit. (По всей вероятности, блокировка - это сам таймер обратного отсчета.) Если в течение этого периода времени сделан другой запрос, он должен быть поставлен в очередь до тех пор, пока таймер обратного отсчета не достигнет нуля и блокировка не будет снята; в этот момент отправляется самый старый запрос в очереди, таймер обратного отсчета сбрасывается, и блокировка снова активируется.
Это случай для многопоточности? Есть ли другой подход, которого я не вижу?
Должны ли таймер обратного отсчета и блокировка быть переменными экземпляра или они должны принадлежать классу, чтобы все экземпляры класса удерживали запросы?
Кроме того, является ли вообще плохая идея предоставлять функциональные возможности ограничения скорости в библиотеке? Я рассуждаю, поскольку по умолчанию обратный отсчет равен нулю секунд, библиотека по-прежнему позволяет разработчикам использовать библиотеку и предоставлять свои собственные схемы ограничения скорости. Однако, учитывая, что любым разработчикам, использующим службу, все равно придется ограничивать скорость запросов, я полагаю, что для библиотеки было бы удобно предоставить средства ограничения скорости.
Независимо от того, размещаю ли в библиотеке схему ограничения скорости или нет, я хочу написать приложение, использующее библиотеку, поэтому предлагаемые методы пригодятся.
Большое спасибо за ваши предложения!
Крис






Это лучше работает с очередью и диспетчером.
Вы разделяете обработку на две части: источник и отправлять. Это могут быть отдельные потоки (или отдельные процессы, если это проще).
Сторона Источник создает запросы и ставит их в очередь с любой скоростью, которая их устраивает.
Это делает сторона Отправлять.
Получите время начала запроса, s.
Удаляет запрос из очереди, обрабатывает запрос через удаленную службу.
Получите текущее время, т. Сон на показатель - (т - s) секунд.
Если вы хотите, чтобы сторона Источник была подключена напрямую к удаленной службе, вы можете сделать это и обойти ограничение скорости. Это хорошо для внутреннего тестирования с помощью фиктивной версии удаленной службы.
Самая сложная часть этого - создание некоторого представления для каждого запроса, который вы можете поставить в очередь. Поскольку Python Очередь справится практически со всем, вам не нужно много делать.
Если вы используете многопроцессорную обработку, вам придется соленый огурец ваших объектов, чтобы поместить их в конвейер.
На вашу схему ограничения скорости должны сильно влиять соглашения о вызовах базового кода (синхронный или асинхронный), а также то, в какой области (поток, процесс, машина, кластер?) Будет работать это ограничение скорости.
Я бы посоветовал сохранить все переменные внутри экземпляра, чтобы вы могли легко реализовать несколько периодов / уровней контроля.
Наконец, похоже, что вы хотите быть компонентом промежуточного программного обеспечения. Не пытайтесь быть приложением и самостоятельно вводить темы. Просто заблокируйте / спите, если вы синхронны, и используйте фреймворк асинхронной диспетчеризации, если вас вызывает один из них.
Очередь может быть слишком сложной. Более простое решение - дать вашему классу переменную для времени последнего вызова службы. При каждом вызове службы (! 1) установите для параметра waitTime значение delay - Now + lastcalltime. delay должен быть равен минимально допустимому времени между запросами. Если это число положительное, поспите так долго, прежде чем вызвать (! 2). Недостатком / преимуществом этого подхода является то, что он обрабатывает запросы веб-службы как синхронные. Преимущество в том, что это абсурдно просто и легко реализовать.
Решение С.Лотта, конечно, более элегантно.
Если ваша библиотека спроектирована так, чтобы быть синхронной, я бы рекомендовал не применять ограничение (хотя вы можете отслеживать скорости и, по крайней мере, помочь вызывающему абоненту решить, как соблюдать ограничения).
В настоящее время я использую скрученный для взаимодействия практически со всем. Это упрощает выполнение таких задач, имея модель, которая отделяет отправку запроса от обработки ответа. Если вы не хотите, чтобы пользователи вашего API использовали twisted, вам, по крайней мере, лучше понять их API для отложенного выполнения.
Например, у меня есть интерфейс твиттера, который отправляет довольно абсурдное количество запросов от имени xmpp пользователи. Я не ограничиваю скорость, но мне пришлось немного поработать, чтобы все запросы не выполнялись одновременно.
Итак, я предполагаю что-то простое, например время импорта время сна (2) не будет ждать 2 секунды между запросами
Что ж, ожидание 2 секунды между концом одного и началом другого может быть безопаснее, если ограничения установлены на основе фактического времени между вызовами. Реальная проблема заключается в том, что ваше решение ждет более 2 секунд между запросами, поскольку вычисление между запросами может занять время.
Не изобретайте велосипед, если в этом нет необходимости. Проверьте замечательную библиотеку ratelimit. Идеально, если вы просто хотите ограничить свои звонки до API отдыха по какой-либо причине и продолжить свою жизнь.
Большое спасибо, @vidstige. Я бился головой о стену, чтобы реализовать решение для ограничения скорости в 60 минут в минуту.
Плохое предположение. Ждет 2 секунды. Это будет 2 секунды. между концом одного и началом другого. Обычно вам нужно 2 секунды. между запуском одного и запуском другого.