Хобрук: Ваш путь к мастерству в программировании

Служба Windows регулярно создает поток до максимума

Я прочитал сотни страниц и использовал так много примеров, что совершенно запутался. Большинство примеров, по-видимому, нацелены на следующее:

  • Пусть таймер создаст новый поток, который будет выполнять некоторую работу, с бесконечными потоками.
  • Создайте определенное количество потоков, каждый с таймером, который что-то делает
  • Регулярно выполняйте какую-либо работу

То, что я пытаюсь сделать, это:

  • Запустите таймер для регулярного создания потока
  • Этот поток может или не может занять больше времени, чем тик таймера
  • Имейте ограничение на количество потоков, которые могут быть созданы
  • Когда поток заканчивается, верните поток, чтобы его можно было использовать снова.
  • Работа в каждом потоке не зависит друг от друга и может выполняться асинхронно (это не имеет большого значения).

В качестве аналогии я хочу, чтобы мое приложение работало как рыбацкая лодка с 10 лесками. Сначала выбрасываете одну (по требованию), затем другую и так далее. В каждый момент времени в воде может находиться от 0 до 10 лесок. Всякий раз, когда рыба поймана, леска натягивается и готова к повторному забросу (если есть необходимость).

Похоже, я должен использовать ThreadPool? Я также думал, что для простоты я должен создать поток и, если нет работы, немедленно вернуть его (т.е. выбрать количество из какой-либо таблицы и, если количество равно 0, вернуть поток), вместо того, чтобы пытаться разумно выяснить если мне нужно спавнить, потому что есть необходимость.

В общем, когда система спокойна, она будет постоянно порождать один поток, видеть, что работы нет, а затем возвращаться, но в периоды занятости потоки, вероятно, будут использоваться до предела, из-за чего система просто будет продолжать давать сбои. для порождения новых потоков до тех пор, пока один или несколько не будут возвращены снова, когда они будут завершены.

Я пробовал System.Threading, Semaphores и WaitHandles, но все это ужасно сбивает с толку. У меня пока нет кода для показа, так как я продолжаю удалять и начинать заново, используя другой подход. Любая помощь будет оценена по достоинству.

Разрабатываю на С# 2010.

29.07.2011

Ответы:


1

Я получил что-то вроде этого, прежде чем использовать пул потоков и таймер:

public class MaxThreadCountWorker : IDisposable
{
    private readonly int _maxThreadCount;
    private readonly int _tickIntervalMilliseconds;
    private readonly Action _periodicWork;
    private readonly System.Threading.Timer _timer;
    private int _currentActiveCount;

    public MaxThreadCountWorker(int maxThreadCount, int tickIntervalMilliseconds, Action periodicWork)
    {
        _maxThreadCount = maxThreadCount;
        _tickIntervalMilliseconds = tickIntervalMilliseconds;
        _periodicWork = periodicWork;
        _timer = new System.Threading.Timer(_ => OnTick(), null, Timeout.Infinite, Timeout.Infinite);
        _currentActiveCount = 0;
    }

    public void Start()
    {
        _timer.Change(0, _tickIntervalMilliseconds);
    }

    public void Stop()
    {
        _timer.Change(Timeout.Infinite, Timeout.Infinite);
    }

    private void DoWork()
    {
        try
        {
            _periodicWork.Invoke();
        }
        finally
        {
            Interlocked.Decrement(ref _currentActiveCount);
        }
    }
    private void OnTick()
    {
        _timer.Change(Timeout.Infinite, Timeout.Infinite);
        try
        {
            if (_currentActiveCount >= _maxThreadCount) return;

            Interlocked.Increment(ref _currentActiveCount);
            ThreadPool.QueueUserWorkItem(_ => DoWork());
        }
        finally
        {
            _timer.Change(_tickIntervalMilliseconds, _tickIntervalMilliseconds);
        }
    }

    public void Dispose()
    {
        _timer.Dispose();
    }
} 

class Program
{
    private static object _lockObject = new object();
    private static int _runningTasks = 0;

    private static void PrintToConsole()
    {
        lock (_lockObject)
        {
            _runningTasks += 1;
        }
        try
        {
            Console.WriteLine("Starting work. Total active: {0}", _runningTasks);
            var r = new Random();
            System.Threading.Thread.Sleep(r.Next(3500));                
        } finally
        {
            lock (_lockObject)
            {
                _runningTasks -= 1;
            }                
        }
    }
    static void Main(string[] args)
    {
        using (var w = new MaxThreadCountWorker(3, 150, PrintToConsole))
        {
            w.Start();
            Console.ReadKey();
        }
    }
}
29.07.2011
  • Потрясающий! Я думаю, что это действительно работает! Я проведу еще несколько предварительных тестов, потому что единственный способ увидеть, использует ли он больше (или меньше) потоков, — это загрузить систему (или сбросить нагрузку) и посмотреть, увеличивается или уменьшается использование потоков, но пока это не так. вроде работает :-) 29.07.2011
  • Алун, твой код точен и работает отлично! Если вы хотите, чтобы я упомянул вас в моем коде, пожалуйста, дайте мне знать, я был бы рад «забронзовать» ваше имя там, чтобы все (разработчики) могли его увидеть! 03.08.2011

  • 2

    Я думаю, что вы должны использовать встроенный ThreadPool вместо того, чтобы изобретать свой собственный. Ситуации, которые вы описываете в вопросе, являются частью сложности, необходимой для обработки в пуле потоков, реализованном свойством. Вместо того, чтобы делать это самостоятельно, я думаю, что вы можете много выиграть, используя существующий (если вы не делаете это, чтобы узнать, как работают пулы потоков).

    Чтобы использовать встроенный пул потоков, вы должны вызвать TreadPool.QueueUserWorkItem() в обработчике событий для тика таймера.

    29.07.2011
  • Спасибо, Андерс, моя последняя попытка была на самом деле с ThreadPool, но все происходило так быстро, что я не могу быть уверен, что он на самом деле использует более одного потока, а спящий поток не совсем говорит мне, работает ли он, поэтому я решил спросить мир. Это кажется ужасно простой концепцией, но она ускользает от меня. 29.07.2011

  • 3

    Threadpool - ваш ответ. Реальный вопрос заключается в том, нужна ли вам какая-либо обратная связь из ветки. Если нет, как кажется, кик потоков в пуле потоков, который будет управлять ограничением на количество потоков. А затем просто продолжайте, работая с тиками таймера как с спящим процессом.

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

    И да, запустите ветку, и пусть она решает, есть ли над чем поработать. В этом сценарии это имеет смысл, и нет смысла проверять, нужно ли что-то запускать.

    29.07.2011
  • Образцы такого подхода всегда завершают работу всего приложения (используя некоторый ManualResetEvent), но я бы предпочел просто вернуть поток в пул. Я предполагаю, что мой вопрос (прошу прощения, если я невежественен или звучит глупо!) Как вернуть поток в пул? 29.07.2011
  • Я просматриваю пример 3 в ресурсе MSDN в MSDN, который, кажется, использует то, что вы объяснили, а также то, что сказал Андерс Абель о QueueUserWorkItem. Этот образец, кажется, КОНЕЦ, после достижения предела. Как мне вернуть поток, чтобы пул работал вечно? 29.07.2011
  • Насколько я понимаю, когда вы закончите поток, он будет возвращен в пул. Поэтому, пока контекст пула потоков все еще работает, вы можете повторно использовать потоки, запуская больше рабочих элементов. 29.07.2011
  • Новые материалы

    Понимание СТРУКТУРЫ ДАННЫХ И АЛГОРИТМА.
    Что такое структуры данных и алгоритмы? Термин «структура данных» используется для описания того, как данные хранятся, а алгоритм используется для описания того, как данные сжимаются. И данные, и..

    Как интегрировать модель машинного обучения на ios с помощью CoreMl
    С выпуском новых функций, таких как CoreML, которые упростили преобразование модели машинного обучения в модель coreML. Доступная модель машинного обучения, которую можно преобразовать в модель..

    Создание успешной организации по науке о данных
    "Рабочие часы" Создание успешной организации по науке о данных Как создать эффективную группу по анализу данных! Введение Это обзорная статья о том, как создать эффективную группу по..

    Технологии и проблемы будущей работы
    Изучение преимуществ и недостатков технологий в образовании В быстро меняющемся мире технологии являются решающим фактором в формировании будущего работы. Многие отрасли уже были..

    Игорь Минар из Google приедет на #ReactiveConf2017
    Мы рады сообщить еще одну замечательную новость: один из самых востребованных спикеров приезжает в Братиславу на ReactiveConf 2017 ! Возможно, нет двух других кланов разработчиков с более..

    Я собираюсь научить вас Python шаг за шагом
    Привет, уважаемый энтузиаст Python! 👋 Готовы погрузиться в мир Python? Сегодня я приготовил для вас кое-что интересное, что сделает ваше путешествие более приятным, чем шарик мороженого в..

    Альтернатива шаблону исходящих сообщений для архитектуры микросервисов
    Познакомьтесь с двухэтапным сообщением В этой статье предлагается альтернативный шаблон для папки Исходящие : двухэтапное сообщение. Он основан не на очереди сообщений, а на..