How to change the rate limit whilst using a RateGate?

半城伤御伤魂 提交于 2020-02-04 03:52:27

问题


I am using the concise RateGate class to limit the number of requests I send to a server.

My code looks something like this:

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();
        }
    }
}

Inside the if(MyClass.RateLimitHit), I need to lower the rate limit by 1. Not just the variable RateLimit, but the limit running in the actual RateGate.

In the RateGate class, I see this:

/// <summary>
/// Number of occurrences allowed per unit of time.
/// </summary>
public int Occurrences { get; private set; }

My question is: if I change private set; to set; and add RateGate.Occurrences = RateLimit; after RateLimit--; will this do what I want?

I tried it, but it looks like the RateGate continues to execute at a max rate of 35/s.


回答1:


I wanted to do that too and I found a nice solution by inverting the time and occurences. What does it mean:

Instead of expressing my problem as "I want N occurences per second", I inversed it as "I want 1 occurence per 1/N seconds". That way, instead of modifying the number of occurences (which will always be 1), I could easily change the time unit. I added this method to the class (you could derive too):

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;
    }
}

Mine had to be threadsafe and I needed a way to prevent changes during certain periods, so on your side you may want to remove the lock and dontUpdateBefore param, which means you can just set TimeUnitMilliseconds and this value will be picked up at the next timer tick. Now, to call this, you just need to calculate the new time you want based on the number of occurences you want.

Hope it could fit your needs.

N.




回答2:


The Occurrences value gets passed to a semaphore in the constructor as the maximum count, so changing the property will have no effect on the behavior of that instance.

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);
}

It looks like Occurrences is more of a readonly property that allows you see what was passed in to the constructor.



来源:https://stackoverflow.com/questions/19579935/how-to-change-the-rate-limit-whilst-using-a-rategate

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!