Задача: разработать возможность запускать на выполнение заданное количество операций в секунду.
Требования:
- Решение должно отрабатывать как можно быстрее (иначе в нем теряется смысл)
- Решение должно быть потокобезопасным
В результате у меня получилась функция (естественно в составе отдельного класса), которая возвращает true либо false (разрешение для выполнения).
Общий принцип таков. Есть коллекция отпечатков DateTime. При запросе разрешения проверяется, не превышает ли количество запросов за последнюю секунду максимальное указанное значение. Если превышает, возвращается ложь, иначе в коллекцию добавляется слепок текущей даты и возвращается истина.
Изначально я делал все на основе листов (List<>), но листы имеют динамический набор данных, а значит они расширяются по надобности и при добавлении новых элементов. А надо еще и удалять. Поэтому я решил использовать коллекцию заданного размера. Поэтому от листа решил отказаться в пользу массива. В результате у меня получился функционал круговой коллекции, основанной на массиве, поэтому в итоге я сделал круговую коллекцию.
Получился пул из отпечатков даты заданного размера на основе круговой коллекции.
Класс пула содержит текущий элемент, в котором есть отпечаток даты и ссылка на следующий элемент. Изначально все даты имеют значение по умолчанию.
При запросе разрешения берется следующий от текущего элемент, и к его дате прибавляется 1 секунда. Если дата получается больше текущей даты, значит в пуле нет места и запрос возвращает ложь. Иначе в качестве текущего элемента устанавливается следующий, в новом текущем элементе устанавливается слепок даты и возвращается истина.
Теперь о потоках. Я не придумал ничего лучше, как поставить lock на функцию разрешения.
Вот и все.
Для тестирования я создал метод, который выполняет заданное количество запросов с заданным количеством потоков. Запустил его со следующими параметрами. Количество операций в секунду — 6, количество потоков — 4, количество запросов — 50.
Получились вот такие результаты
Вот ссылка на гитхаб
github.com/iRumba/RpsBarrier
По скрину видно, что код отработал верно.
Автор: Анатолий