Как изменить лимит скорости при использовании RateGate?

Я использую краткий класс RateGate для ограничить количество запросов, которые я отправляю на сервер.

Мой код выглядит примерно так:

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/с.


person Danny Beckett    schedule 25.10.2013    source источник
comment
Просто чтобы уточнить... для вознаграждения вы ищете модифицированный класс RateGate или новый класс, который наследует и переопределяет/расширяет некоторые функции класса RateGate?   -  person Jeff B    schedule 28.10.2013


Ответы (2)


Я тоже хотел это сделать и нашел хорошее решение, инвертировав время и события. Что это значит:

Вместо того, чтобы выражать свою проблему как «Я хочу N вхождений в секунду», я перевернул ее как «Я хочу 1 вхождение в 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, и это значение будет выбрано на следующем таймере. поставить галочку. Теперь, чтобы вызвать это, вам просто нужно рассчитать новое время, которое вы хотите, на основе количества желаемых вхождений.

Надеюсь, это может соответствовать вашим потребностям.

N.

person Nicolas Cadilhac    schedule 28.10.2013
comment
Большое спасибо за ваш ответ Николай, это выглядит многообещающе! Собираюсь проверить это в ближайшее время. - person Danny Beckett; 29.10.2013
comment
Это отлично работает, большое спасибо за идею обратить проблему, чтобы использовать 1 вхождение в (1000/(число в секунду)) миллисекунд. В конце концов, код становится таким же простым, как RateGate.TimeUnitMilliseconds = 1000 / 35; - person Danny Beckett; 29.10.2013
comment
Конечно, public int TimeUnitMilliseconds { get; private set; } также следует изменить с private set; на set;. - person Danny Beckett; 29.10.2013

Значение 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 — это скорее свойство только для чтения, которое позволяет вам видеть, что было передано конструктору.

person Jeff B    schedule 25.10.2013
comment
Спасибо за объяснение, почему это не работает, Джефф; Я не думаю, что у вас есть какие-либо идеи, как я могу изменить максимальный предел скорости, находясь внутри исполняемого RateGate? - person Danny Beckett; 25.10.2013
comment
Я не уверен, что это возможно с текущей договоренностью. Если я правильно понимаю, этот семафор управляет потоком вещей, поэтому, если вы его уничтожите, он сбросит состояние. При этом может быть возможно написать метод (или реализовать набор), чтобы он использовал текущий счетчик существующего семафора при создании нового... что-то вроде: _semaphore = new SemaphoreSlim(_semaphore.CurrentCount, newOccurrenceValue) но я не могу гарантировать его поведение . - person Jeff B; 25.10.2013
comment
Теперь я добавил награду; может быть, вы хотели бы попытаться выяснить, возможно ли это... - person Danny Beckett; 28.10.2013