4

我编写了一个 API 速率限制器来与 Last.fm 的 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请求的好方法吗?

4

2 回答 2

2

在我看来,这很好。除此之外,此代码中有一个错误。这是因为如果每个请求一个接一个地完成超过一秒怎么办?它永远不会进入那个if街区。因此,某种内存泄漏,因为_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);
}
于 2013-06-05T09:30:53.763 回答
2

我写了一个库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 包使用。

于 2016-06-08T15:10:32.710 回答