2011-04-12 18 views

回答

3

我不認爲在內存中的結構就足夠了這裏,因爲你需要測量時間長。在這種情況下,IIS回收會有問題。因此,我建議記錄用戶對數據庫資源的訪問權限,並且只允許在過去24小時內計數100。

在另一方面,這裏是我們實現一個漏桶限幅(這是短期的限制,其中失敗是相對不重要更加得心應手)的。使用.NET 4併發集合可能會改善這種實現中的某種暴力鎖定:

public class RateLimiter 
{ 
    private readonly double numItems; 
    private readonly double ratePerSecond; 
    private readonly Dictionary<object, RateInfo> rateTable = 
     new Dictionary<object, RateInfo>(); 
    private readonly object rateTableLock = new object(); 
    private readonly double timePeriod; 

    public RateLimiter(double numItems, double timePeriod) 
    { 
     this.timePeriod = timePeriod; 
     this.numItems = numItems; 
     ratePerSecond = numItems/timePeriod; 
    } 

    public double Count 
    { 
     get 
     { 
      return numItems; 
     } 
    } 

    public double Per 
    { 
     get 
     { 
      return timePeriod; 
     } 
    } 

    public bool IsPermitted(object key) 
    { 
     RateInfo rateInfo; 
     var permitted = true; 
     var now = DateTime.UtcNow; 
     lock (rateTableLock) 
     { 
      var expiredKeys = 
       rateTable 
       .Where(kvp => 
        (now - kvp.Value.LastCheckTime) 
        > TimeSpan.FromSeconds(timePeriod)) 
       .Select(k => k.Key) 
       .ToArray(); 
      foreach (var expiredKey in expiredKeys) 
      { 
       rateTable.Remove(expiredKey); 
      } 
      var dataExists = rateTable.TryGetValue(key, 
                out rateInfo); 
      if (dataExists) 
      { 
       var timePassedSeconds = (now - rateInfo.LastCheckTime).TotalSeconds; 
       var newAllowance = 
        Math.Min(
         rateInfo.Allowance 
         + timePassedSeconds 
         * ratePerSecond, 
         numItems); 
       if (newAllowance < 1d) 
       { 
        permitted = false; 
       } 
       else 
       { 
        newAllowance -= 1d; 
       } 
       rateTable[key] = new RateInfo(now, 
               newAllowance); 
      } 
      else 
      { 
       rateTable.Add(key, 
           new RateInfo(now, 
              numItems - 1d)); 
      } 

     } 
     return permitted; 
    } 

    public void Reset(object key) 
    { 
     lock (rateTableLock) 
     { 
      rateTable.Remove(key); 
     } 
    } 

    private struct RateInfo 
    { 
     private readonly double allowance; 
     private readonly DateTime lastCheckTime; 

     public RateInfo(DateTime lastCheckTime, double allowance) 
     { 
      this.lastCheckTime = lastCheckTime; 
      this.allowance = allowance; 
     } 

     public DateTime LastCheckTime 
     { 
      get 
      { 
       return lastCheckTime; 
      } 
     } 

     public double Allowance 
     { 
      get 
      { 
       return allowance; 
      } 
     } 
    } 

} 
+2

我強烈建議不要在lock語句之外聲明(並初始化'now')。雖然這是不可能發生的您的應用程序,如果調用線程遭到封鎖很長一段時間對'lock'聲明,你可以比您預期的'IsPermitted'叫什麼得到不同的結果。 – 2012-12-17 14:28:28