API速率限制器

时间:2013-06-05 08:53:52

标签: c# web last.fm system.net.httpwebrequest

我写了一个API速率限制器,用于Last.fm的API。

Last.fm的Tos表示,我每秒发送的IP地址不能超过5个请求,平均时间为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 个答案:

答案 0 :(得分: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);
}

答案 1 :(得分: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