如何限制每个时间的方法使用?
它必须是微不足道的,但我无法通过它。 我必须在一段时间内限制任务量(假设连接,发送的电子邮件或点击按钮)。 所以我可以每小时发送1000封电子邮件。
我怎么能在c#中做到这一点? 我不知道也不关心每次操作需要多少时间。 我只是想确保在最后一小时内,只执行1000次。
class EventLimiter { Queue requestTimes; int maxRequests; TimeSpan timeSpan; public EventLimiter(int maxRequests, TimeSpan timeSpan) { this.maxRequests = maxRequests; this.timeSpan = timeSpan; requestTimes = new Queue (maxRequests); } private void SynchronizeQueue() { while ((requestTimes.Count > 0) && (requestTimes.Peek().Add(timeSpan) < DateTime.UtcNow)) requestTimes.Dequeue(); } public bool CanRequestNow() { SynchronizeQueue(); return requestTimes.Count < maxRequests; } public void EnqueueRequest() { while (!CanRequestNow()) Thread.Sleep(requestTimes.Peek().Add(timeSpan).Subtract(DateTime.UtcNow)); // Was: System.Threading.Thread.Sleep(1000); requestTimes.Enqueue(DateTime.UtcNow); } }
假设滚动小时窗口:
维护动作何时完成的列表。
每次要执行操作时,请在一小时内删除列表中的所有内容。
如果少于1000,则执行操作并将记录添加到列表中。
假设每小时:
创建一个代理方法和一个为每个操作递增的变量,并在一小时内减少到零。
如果计数器<1000,请执行您的操作。
您可以使用Rx扩展( 如何在Rx中使用新的BufferWithTimeOrCount返回IObservable
上面的解决方案看起来不错 这是我的修剪版本:
public class EmailRateHelper { private int RequestsPerInterval = 30; private Queue History = new Queue (); private TimeSpan Interval = new TimeSpan(0, 1, 0); public EmailRateHelper() { } public EmailRateHelper(int RequestsPerInterval, TimeSpan Interval) { this.RequestsPerInterval = RequestsPerInterval; this.Interval = Interval; } public void SleepAsNeeded() { DateTime _Now = DateTime.Now; History.Enqueue(_Now); if (History.Count >= RequestsPerInterval) { var _Last = History.Dequeue(); TimeSpan Difference = _Now - _Last; if (Difference < Interval) System.Threading.Thread.Sleep(Interval - Difference); } } }
您还可以考虑将{action,time,user}信息存储在数据库中,并在需要处理应用程序池重启/崩溃的情况下,在数据库(或类似的持久存储器)的最后一小时内获取操作数。 否则,聪明的用户可能会因服务器过载而绕过内存中的保护。
您可以为每个用户创建持久计数器。 每次收到请求(发送电子邮件)时,您都需要检查计数器的值和创建计数器的日期。
- 如果计数大于限制,则拒绝该请求
- 如果日期早于一小时,则重置计数器并设置新的创建日期
- 如果日期正确且计数低于限制,则增加计数器
仅在最后两种情况下执行请求。