2013-06-05 207 views
3

我写了一个API速率限制器,可以与Last.fm的API一起使用。API速率限制器

Last.fm的Tos指出,我不能每秒发出超过5个请求,每秒发起IP地址的平均时间为5分钟。

这里是我写的类:

public class RateLimiter 
{ 
    private static readonly List<DateTime> _requests = new List<DateTime>(); 

    private const double _perMillisecond = 1000.1; 
    private const int _rateLimit = 5; 
    private const int _rateLimitCooldownMs = 500; 

    public static void CheckLimiter() 
    { 
     _requests.Add(DateTime.Now); 

     var requestsDuringRateLimit = _requests.Where(w => (DateTime.Now - w).TotalMilliseconds < _perMillisecond).ToArray(); 

     if (requestsDuringRateLimit.Count() >= _rateLimit) 
     { 
      Thread.Sleep(_rateLimitCooldownMs); 
      _requests.Clear(); 
      Console.Clear(); 
     } 
    } 
} 

CheckLimiter方法是HttpWebRequest之前调用启动,则此限制API请求的好方法?

回答

2

在我看来这很好。除此之外,此代码中存在一个错误。这是因为如果每个请求都相继完成超过一秒钟,该怎么办?它永远不会进入该if块。因此,某种memory leak,因为_requests将随着时间的推移而变大,并且如果我的场景总是发生,可能永远不会被清除。

例子:

for (int i = 0; i < 100; i++) 
{ 
    RateLimiter.CheckLimiter(); 
    Thread.Sleep(2000); 
} 

你可以做的是去除你_requests被超过喜欢加入这一行,在你的方法结束1秒规则条目。

if (_requests.Count != 0) 
{ 
    //remove irrelevant/expired entries 
    _requests.RemoveAll(date => (DateTime.Now - date).TotalMilliseconds >= _perMillisecond); 
} 
+0

是的,我注意到,我发布后......谢谢! :) – jjdev80

1

我写了一个库RateLimiter来处理这种约束。我们提出的解决方案的主要优点是它是异步和可取消的。另一个特点是你可以编写约束来构建复杂的约束。

样品:

var timeconstraint = TimeLimiter.GetFromMaxCountByInterval(5, TimeSpan.FromSeconds(1)); 

for(int i=0; i<1000; i++) 
{ 
    await timeconstraint.Perform(ConsoleIt); 
}  

.... 
private Task ConsoleIt() 
{ 
    Trace.WriteLine(string.Format("{0:MM/dd/yyy HH:mm:ss.fff}", DateTime.Now)); 
    return Task.FromResult(0); 
} 

组成:

var constraint = new CountByIntervalAwaitableConstraint(5, TimeSpan.FromSeconds(1)); 

//Create second constraint: one time each 100 ms 
var constraint2 = new CountByIntervalAwaitableConstraint(1, TimeSpan.FromMilliseconds(100)); 

//Compose the two constraints 
var timeconstraint = TimeLimiter.Compose(constraint, constraint2); 

//Use it 
for(int i=0; i<1000; i++) 
{ 
    await timeconstraint.Perform(ConsoleIt); 
} 

它也可以作为一个nuget package