我需要限制时间段deltaT期间允许的事件数n。我能想到的任何方法,空间都是O(m),其中m是每个deltaT或O(deltaT/r)发送的最大事件请求数,其中r是可接受的分辨率。
编辑:deltaT 是相对于时间戳的滑动时间窗口。
例如:保持事件时间戳的循环缓冲区。在事件裁剪所有比t-deltaT更早的时间戳。如果时间戳数超过n则拒绝事件。将时间戳添加到缓冲区。
或者,初始化一个大小为deltaT/r的整数的循环桶缓冲区,该缓冲区按相对于当前分辨率r的时间进行索引。维护指针i。发生事件时, i自上次事件以来的时间除以r递增。将原始i和新 i 之间的缓冲区归零。在i处增加。拒绝,如果错误的总和超过n。
有什么更好的方法?
我刚刚在 c# 中实现了我上面的第二个建议,固定deltaT为 1 s,固定分辨率为 10 ms。
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;
}
}