我使用简洁的RateGate class来限制发送给服务器的请求数。
我的代码看起来像这样:
var RateLimit = 35;
using(var RateGate = new RateGate(RateLimit, TimeSpan.FromSeconds(1)))
{
for(var Run = 1; Run <= 50; Run++)
{
for(var Batch = 0; Batch < 200; Batch++)
{
// Do some work, then...
MyClass MyClass;
if(MyClass.RateLimitHit)
{
RateLimit--;
}
RateGate.WaitToProceed();
}
}
}
在if(MyClass.RateLimitHit)
内,我需要将速率限制降低1.不仅仅是变量RateLimit
,而是在实际RateGate
中运行限制。
在RateGate类中,我看到了:
/// <summary>
/// Number of occurrences allowed per unit of time.
/// </summary>
public int Occurrences { get; private set; }
我的问题是:如果我将private set;
更改为set;
并在RateGate.Occurrences = RateLimit;
之后添加RateLimit--;
,这会做我想要的吗?
我尝试了,但看起来RateGate
继续以35 / s的最高速率执行。
答案 0 :(得分:2)
我也想这样做,我通过反转时间和出现找到了一个很好的解决方案。 这是什么意思:
我没有将我的问题表达为“我希望每秒出现N次”,而是将其反转为“我希望每1 / N秒出现一次”。这样,我可以轻松地改变时间单位,而不是修改出现次数(总是为1)。我在课堂上添加了这个方法(你也可以推导出来):
private object _updateTimeUnitLock = new object();
private int nextUpdateTime = 0;
public bool UpdateTimeUnit(TimeSpan timeUnit, TimeSpan dontUpdateBefore)
{
lock (_updateTimeUnitLock)
{
if ((nextUpdateTime == 0) || (nextUpdateTime <= Environment.TickCount))
{
TimeUnitMilliseconds = (int)timeUnit.TotalMilliseconds;
nextUpdateTime = Environment.TickCount + (int)dontUpdateBefore.TotalMilliseconds;
return true;
}
return false;
}
}
我必须是线程安全的,我需要一种方法来防止在某些时期发生变化,所以在你这边你可能想要删除锁和dontUpdateBefore
参数,这意味着你可以设置TimeUnitMilliseconds,这个值将在下一个计时器勾选时被拿起。
现在,要调用它,您只需根据所需的出现次数计算所需的新时间。
希望它能满足您的需求。
<磷>氮答案 1 :(得分:1)
Occurrences
值作为最大计数传递给构造函数中的信号量,因此更改属性不会影响该实例的行为。
public RateGate(int occurrences, TimeSpan timeUnit)
{
// Snipped all the code that doesn't pertain to this question...
Occurrences = occurrences;
// Create the semaphore, with the number of occurrences as the maximum count.
_semaphore = new SemaphoreSlim(Occurrences, Occurrences);
}
看起来Occurrences更像是一个只读属性,可以让你看到传递给构造函数的内容。