我写了一个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请求的好方法吗?
答案 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。