Есть ли лучший способ ограничить работу с высокой пропускной способностью? - PullRequest
4 голосов
/ 12 марта 2010

Я создал простой класс, который показывает, что я пытаюсь сделать без шума. Не стесняйтесь оскорблять мой код. Вот почему я разместил это здесь.

public class Throttled : IDisposable
{
    private readonly Action work;
    private readonly Func<bool> stop;
    private readonly ManualResetEvent continueProcessing;
    private readonly Timer throttleTimer;
    private readonly int throttlePeriod;
    private readonly int throttleLimit;
    private int totalProcessed;

    public Throttled(Action work, Func<bool> stop, int throttlePeriod, int throttleLimit)
    {
        this.work = work;
        this.stop = stop;
        this.throttlePeriod = throttlePeriod;
        this.throttleLimit = throttleLimit;
        continueProcessing = new ManualResetEvent(true);
        throttleTimer = new Timer(ThrottleUpdate, null, throttlePeriod, throttlePeriod);
    }

    public void Dispose()
    {
        throttleTimer.Dispose();
        ((IDisposable)continueProcessing).Dispose();
    }

    public void Execute()
    {
        while (!stop())
        {
            if (Interlocked.Increment(ref totalProcessed) > throttleLimit)
            {
                lock (continueProcessing)
                {
                    continueProcessing.Reset();
                }
                if (!continueProcessing.WaitOne(throttlePeriod))
                {
                    throw new TimeoutException();
                }
            }

            work();
        }
    }

    private void ThrottleUpdate(object state)
    {
        Interlocked.Exchange(ref totalProcessed, 0);
        lock (continueProcessing)
        {
            continueProcessing.Set();
        }
    }
}

Последний код

public class Throttled
{
    private readonly Func<bool> work;
    private readonly ThrottleSettings settings;
    private readonly Stopwatch stopwatch;
    private int totalProcessed;

    public Throttled(Func<bool> work, ThrottleSettings settings)
    {
        this.work = work;
        this.settings = settings;
        stopwatch = new Stopwatch();
    }

    private void Execute()
    {
        stopwatch.Start();
        while (work())
        {
            if (++totalProcessed > settings.Limit)
            {
                var timeLeft = (int)(settings.Period - stopwatch.ElapsedMilliseconds);
                if (timeLeft > 0)
                {
                    Thread.Sleep(timeLeft);
                }
                totalProcessed = 0;
                stopwatch.Reset();
                stopwatch.Start();
            }
        }
    }
}

Ответы [ 2 ]

1 голос
/ 12 марта 2010

Прежде всего, я бы полностью избавился от управляющего потока, потому что его работа может быть легко выполнена перед вызовом work().

Тогда я бы сделал рабочий поток отличным от основного, таким образом разблокируя основной поток для других задач. Далее я бы добавил функцию для отмены обработки, которая, возможно, установит флажок проверенного рабочего потока.

Edit:
Согласно комментариям, наша цель - ограничить количество work() вызовов во время каждого throttlePeriod тиков. Мы можем сделать это лучше, отмечая время в секундомере, сравнивая его после throttleLimit рабочих операций и оставаясь в спящем режиме. Таким образом, нам снова не нужен поток таймера.

Редактировать: (удалено, неверно)
Изменить:
Мы можем сделать даже некоторый баланс: находясь в пределах throttlePeriod, мы вычисляем, сколько времени заняло work(), поэтому мы можем оценить, сколько времени займет все оставшиеся work(), и ждать каждый два work() s равная доля оставшегося времени. Это заставит нас не очень быстро выполнять все work() в начале выделенного периода, возможно, блокируя БД.

0 голосов
/ 12 марта 2010

Почему газ? и зачем Sleep (), когда вы можете поставить поток с более низким приоритетом и заставить его поглощать ВСЕ неиспользуемые циклы ЦП, чтобы выполнять свою работу как можно быстрее, не прерывая работу с более высоким приоритетом?

На самом деле, почему бы не назначить всем потокам, не относящимся к пользовательскому интерфейсу, более низкий приоритет, чтобы ваше приложение в целом оставалось отзывчивым?

Единственное предостережение здесь - если вы выполняете ввод-вывод - доступ к диску должен быть ограничен, чтобы все остальное работало гладко.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...