如何限制每个时间的方法使用?

它必须是微不足道的,但我无法通过它。 我必须在一段时间内限制任务量(假设连接,发送的电子邮件或点击按钮)。 所以我可以每小时发送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 >而不是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}信息存储在数据库中,并在需要处理应用程序池重启/崩溃的情况下,在数据库(或类似的持久存储器)的最后一小时内获取操作数。 否则,聪明的用户可能会因服务器过载而绕过内存中的保护。

您可以为每个用户创建持久计数器。 每次收到请求(发送电子邮件)时,您都需要检查计数器的值和创建计数器的日期。

  • 如果计数大于限制,则拒绝该请求
  • 如果日期早于一小时,则重置计数器并设置新的创建日期
  • 如果日期正确且计数低于限制,则增加计数器

仅在最后两种情况下执行请求。