簡體   English   中英

如何限制每次使用方法的時間?

[英]How to limit method usage per amount of time?

它必須是瑣碎的,但我只是無法解決。 我必須限制每個時間的任務量(比如連接,發送的電子郵件或單擊按鈕)。 因此,例如,我每小時可以發送1000封電子郵件。

我該如何在C#中做到這一點? 我不知道,也不在乎每個操作要花費多少時間。 我只想確保最后一個小時只能執行1000個。

 class EventLimiter
 {
    Queue<DateTime> requestTimes;
    int maxRequests;
    TimeSpan timeSpan;

    public EventLimiter(int maxRequests, TimeSpan timeSpan)
    {
        this.maxRequests = maxRequests;
        this.timeSpan = timeSpan;
        requestTimes = new Queue<DateTime>(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,請執行操作。

上述解決方案看起來不錯。 這是我的精簡版本:

public class EmailRateHelper
{
    private int _requestsPerInterval;
    private Queue<DateTime> _history;
    private TimeSpan _interval;

    public EmailRateHelper()
        : this(30, new TimeSpan(0, 1, 0)) { }

    public EmailRateHelper(int requestsPerInterval, TimeSpan interval)
    {
        _requestsPerInterval = requestsPerInterval;
        _history = new Queue<DateTime>();
        _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);
            }
        }
    }
}

您可以使用Rx擴展( 如何在Rx中使用新的BufferWithTimeOrCount返回IObservable <IObservable <T >>而不是IObservable <IList <T >> ),但是我將通過添加適當的代理對象來手動實現緩沖。

如果需要處理應用程序池重啟/崩潰,您還可以考慮在數據庫中存儲{action,time,user}信息,並在數據庫(或類似的持久性存儲器)的最后一小時內獲取操作數。 否則,聰明的用戶可能會因服務器超載而繞過內存保護。

您可以為每個用戶創建一個持久計數器。 每次收到請求(發送電子郵件)時,都需要檢查計數器的值和計數器的創建日期。

  • 如果計數大於限制,則您拒絕請求
  • 如果日期早於一個小時,則重置計數器並設置新的創建日期
  • 如果日期正確且計數在限制范圍內,則增加計數器

僅在最后兩種情況下才執行請求。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM