Мне нужно ограничить количество событий n, разрешенных в течение периода времени deltaT. При любом подходе, который я могу придумать, пространство равно O(m), где m — максимальное количество событийных запросов, отправляемых на deltaT, или O(deltaT/r), где r — приемлемое разрешение.
Редактировать: deltaT - это скользящее временное окно относительно метки времени.
Например: Сохраняйте круговой буфер временных меток событий. При событии обрезаются все временные метки, предшествующие t-deltaT. Отклонить событие, если количество меток времени превышает n. Добавьте метку времени в буфер.
Или создайте кольцевой буфер из целых чисел размером deltaT/r, индексированных по времени относительно текущего с разрешением r. Поддерживать указатель i. По событию увеличивайте i на время, прошедшее с момента последнего события, деленное на r. Обнулить буфер между исходным i и новым. Увеличение на i. Отклонить, если сумма ошибок превышает n.
Какой способ лучше?
Я только что реализовал свое второе предложение выше на С# с фиксированным значением deltaT в 1 с и фиксированным разрешением в 10 мс.
public class EventCap
{
private const int RES = 10; //resolution in ms
private int _max;
private readonly int[] _tsBuffer;
private int p = 0;
private DateTime? _lastEventTime;
private int _length = 1000 / RES;
public EventCap(int max)
{
_max = max;
_tsBuffer = new int[_length];
}
public EventCap()
{
}
public bool Request(DateTime timeStamp)
{
if (_max <= 0)
return true;
if (!_lastEventTime.HasValue)
{
_lastEventTime = timeStamp;
_tsBuffer[0] = 1;
return true;
}
//A
//Mutually redundant with B
if (timeStamp - _lastEventTime >= TimeSpan.FromSeconds(1))
{
_lastEventTime = timeStamp;
Array.Clear(_tsBuffer, 0, _length);
_tsBuffer[0] = 1;
p = 0;
return true;
}
var newP = (timeStamp - _lastEventTime.Value).Milliseconds / RES + p;
if (newP < _length)
Array.Clear(_tsBuffer, p + 1, newP - p);
else if (newP > p + _length)
{
//B
//Mutually redundant with A
Array.Clear(_tsBuffer, 0, _length);
}
else
{
Array.Clear(_tsBuffer, p + 1, _length - p - 1);
Array.Clear(_tsBuffer, 0, newP % _length);
}
p = newP % _length;
_tsBuffer[p]++;
_lastEventTime = timeStamp;
var sum = _tsBuffer.Sum();
return sum <= 10;
}
}