首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >滚动时间窗口

滚动时间窗口
EN

Stack Overflow用户
提问于 2019-09-18 13:28:20
回答 1查看 87关注 0票数 0

我有一个系统,在这个系统中,用户可以在给定的时间范围内完成3次请求。如何在C#中对其进行编程?我知道我可以只给用户3个属性(DateTime1,DateTime2,DateTime3),然后检查这些属性,但这感觉是错误的。有没有更聪明的方法呢?我也在考虑使用堆栈或队列,但不知道如何使用。如果时间框架和请求限制都可以临时更改(这样就没有单独的属性),那就太好了。

示例:窗口为60分钟

用户%1已用完时间限制,访问被拒绝。用户2尚未用完限制,因此可以接受。

如前所述,时间框架是滚动的。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-09-18 14:41:03

您可以定义自己的RollingTimeWindow类,该类记录最近成功的请求,并且只有在时间允许的情况下才执行请求。

您可以使用以下代码对其进行测试。按ENTER键尝试执行请求,只有在时间窗口允许的情况下才会执行。

代码语言:javascript
复制
static void Main(string[] args) {
    //Only allow 3 requests in a time window of 10 seconds.
    var r = new RollingTimeWindow(3, TimeSpan.FromSeconds(10), () => Console.WriteLine("Executed."));
    while (true) {
        Console.ReadLine(); //wait for press on Enter
        r.PerformRequest();
    }
}

这是一个简单的代码,让您开始处理滚动时间窗口:

代码语言:javascript
复制
public class RollingTimeWindow {
    private Queue<DateTime> _latestRequests = new Queue<DateTime>();
    private readonly int _maxNumberOfRequests;
    private readonly TimeSpan _windowSize;
    private Action _action;

    /// <summary>
    /// Creates a new RollingTimeWindow performing requests if allowed by the time frame.
    /// </summary>
    /// <param name="maximumNumberOfRequests">Number of requests allowed in the window size</param>
    /// <param name="windowSize">Rolling window size</param>
    /// <param name="requestAction">Action to invoke when the request must be performed</param>
    public RollingTimeWindow(int maximumNumberOfRequests, TimeSpan windowSize, Action requestAction = default) {
        _action = requestAction;
        _maxNumberOfRequests = maximumNumberOfRequests;
        if (_maxNumberOfRequests < 0) {
            throw new ArgumentException(nameof(maximumNumberOfRequests));
        }
        _windowSize = windowSize;
    }

    //Returns true if the request would be allowed, else false (NOT threadsafe)
    public bool IsRequestAllowed() {
        CleanQueue(DateTime.Now);
        return _latestRequests.Count < _maxNumberOfRequests;
    }

    //Returns true if the request was performed, else false.
    public bool PerformRequest() {
        var now = DateTime.Now;
        CleanQueue(now);
        if (_latestRequests.Count < _maxNumberOfRequests) {
            _latestRequests.Enqueue(now);
            _action(); //perform the actual request
            return true;
        } else {
            return false; //request not allowed
        }
    }

    private void CleanQueue(DateTime now) {
        //Cleans all requests older than the window size
        while (_latestRequests.Count > 0 && _latestRequests.Peek() < now - _windowSize) {
            _latestRequests.Dequeue();
        }
    }
}

请注意,这不是线程安全的,而且它也可以使用Timer对象来实现,以自动将较旧的值出队。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57985646

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档