Когда использовать пул streamов в C #?

Я пытаюсь изучить многопоточное программирование на C #, и я смущен, когда лучше использовать пул streamов или создавать собственные streamи. Одна книга рекомендует использовать пул streamов только для небольших задач (что бы это ни значило), но я не могу найти никаких реальных рекомендаций. Каковы некоторые соображения, которые вы используете при принятии этого решения?

Если у вас много логических задач, требующих постоянной обработки, и вы хотите, чтобы это было сделано параллельно, используйте пул + планировщик.

Если вам нужно одновременно выполнять связанные с IO задачи, такие как загрузка файлов с удаленных серверов или доступ к диску, но вам нужно сделать это один раз каждые несколько минут, а затем создать свои собственные streamи и убить их, как только вы закончите.

Edit: О некоторых соображениях я использую пулы streamов для доступа к базе данных, физику / симуляцию, AI (игры) и для сценариев задач, выполняемых на виртуальных машинах, которые обрабатывают множество пользовательских задач.

Обычно пул состоит из 2 streamов на процессор (так вероятно 4 в настоящее время), однако вы можете настроить количество streamов, которые вы хотите, если знаете, сколько вам нужно.

Изменить: причина для создания собственных streamов связана с изменениями контекста (это когда streamи должны меняться и выходить из процесса вместе с их памятью). Имея бесполезные изменения в контексте, скажите, когда вы не используете свои streamи, просто оставляя их сидеть, как можно было бы сказать, может легко выполнить половину производительности вашей программы (скажем, у вас 3 спальных streamа и 2 активных streamа). Таким образом, если пользователи, загружающие streamи, просто ждут, они съедят тонны процессора и охладят кеш для вашего реального приложения

Я бы предложил использовать пул streamов в C # по тем же причинам, что и любой другой язык.

Если вы хотите ограничить количество запущенных streamов или не хотите накладных расходов на их создание и уничтожение, используйте пул streamов.

Маленькими задачами книга, которую вы читаете, означает задачи с коротким сроком службы. Если для создания streamа, который работает только одна секунда, требуется десять секунд, это одно место, где вы должны использовать пулы (игнорируйте мои фактические цифры, это отношение, которое учитывается).

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

Вот хорошее резюме пула streamов в .Net: http://blogs.msdn.com/pedram/archive/2007/08/05/dedicated-thread-or-a-threadpool-thread.aspx

Сообщение также имеет некоторые моменты, когда вы не должны использовать пул streamов и вместо этого запускать свой собственный stream.

Я настоятельно рекомендую прочитать эту бесплатную электронную книгу: Threading in C # by Joseph Albahari

По крайней мере, прочитайте раздел «Начало работы». Электронная книга обеспечивает отличное введение и включает в себя богатую передовую информацию о streamах.

Знание того, следует ли использовать пул streamов, – это только начало. Затем вам нужно будет определить, какой метод ввода пула streamов наилучшим образом соответствует вашим потребностям:

  • Параллельная библиотека задач (.NET Framework 4.0)
  • ThreadPool.QueueUserWorkItem
  • Асинхронные delegates
  • BackgroundWorker

Эта электронная книга объясняет все это и советует, когда использовать их или создавать свой собственный stream.

Пул streamов предназначен для уменьшения переключения контекста между вашими streamами. Рассмотрим процесс, в котором работает несколько компонентов. Каждый из этих компонентов может создавать рабочие streamи. Чем больше streamов в вашем процессе, тем больше времени тратится на переключение контекста.

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

Пул streamов предназначен для максимизации работы, выполняемой через ваши процессоры (или ядра ЦП). Вот почему по умолчанию пул streamов объединяет несколько streamов на процессор.

Есть ситуации, когда вы не хотите использовать пул streamов. Если вы ждете ввода / вывода или ожидаете события, и т. Д., То вы связываете этот stream streamа streamов и не можете использовать кто-либо еще. Такая же идея относится к длительным задачам, хотя то, что составляет долговременную задачу, является субъективным.

Pax Diablo тоже хорошо подходит. Спиннинг streamов не является бесплатным. Это требует времени, и они потребляют дополнительную память для своего пространства стека. Пул streamов будет повторно использовать streamи, чтобы амортизировать эту стоимость.

Примечание: вы попросили использовать stream пула streamов для загрузки данных или выполнения операций ввода-вывода. Вы не должны использовать stream пула streamов для этого (по причинам, изложенным выше). Вместо этого используйте asynchronous ввод-вывод (также метод BeginXX и EndXX). Для FileStream , который будет BeginRead и EndRead . Для HttpWebRequest , который будет BeginGetResponse и EndGetResponse . Их сложнее использовать, но они являются надлежащим способом выполнения многопоточных операций ввода-вывода.

Остерегайтесь пула streamов .NET для операций, которые могут блокировать любую значительную, переменную или неизвестную часть их обработки, поскольку она подвержена streamу голода. Рассмотрим использование параллельных расширений .NET, которые обеспечивают большое количество логических абстракций над streamовыми операциями. Они также include новый планировщик, который должен быть улучшен в ThreadPool. См. Здесь

Одна из причин использования пула streamов для небольших задач заключается только в том, что существует ограниченное количество streamов пулов streamов. Если он используется в течение длительного времени, он останавливает использование этого streamа другим кодом. Если это происходит много раз, пул streamов может израсходовать.

Использование пула streamов может иметь тонкие эффекты – некоторые таймеры .NET используют streamи пула streamов и не запускают, например.

Для максимальной производительности с одновременным выполнением единиц создайте свой собственный пул streamов, когда пул объектов Thread создается при запуске и переходит к блокировке (ранее приостановленному), ожидая в контексте запуска (объект со стандартным интерфейсом, реализованный ваш код).

Так много статей о Tasks vs. Threads и .NET ThreadPool не могут дать вам то, что вам нужно, чтобы принять решение о производительности. Но когда вы их сравниваете, Threads выигрывают и особенно пул streamов. Они распределены лучше всего по процессорам, и они запускаются быстрее.

Что нужно обсудить, так это то, что основной исполнительный блок Windows (включая Windows 10) является streamом, а перераспределение служебных сообщений ОС обычно незначительно. Проще говоря, я не смог найти убедительных доказательств многих из этих статей, независимо от того, утверждает ли статья более высокую производительность, экономя переключение контекста или улучшая использование ЦП.

Теперь для немного реализма:

Большинство из нас не будут нуждаться в том, чтобы наше приложение было детерминированным, и большинство из нас не сталкиваются с проблемами с streamами, которые, например, часто возникают при разработке операционной системы. То, что я написал выше, не для новичка.

Поэтому наиболее важным является обсуждение того, что легко программировать.

Если вы создадите свой собственный пул streamов, у вас будет немного записи, так как вам нужно будет отслеживать статус выполнения отслеживания, как имитировать приостановку и возобновление работы, и как отменить выполнение – в том числе в общепринятой неисправность. Возможно, вам также придется беспокоиться о том, хотите ли вы динамически наращивать свой пул, а также то, что ограничить емкость вашего пула. Я могу написать такую ​​структуру через час, но это потому, что я делал это так много раз.

Возможно, самый простой способ написать блок исполнения – использовать задачу. Красота Задачи состоит в том, что вы можете создать ее и выставить ее в строке в своем коде (хотя осторожность может быть оправдана). Вы можете передать маркер отмены, чтобы обрабатывать, когда хотите отменить задачу. Кроме того, он использует обещающий подход к цепочке событий, и вы можете вернуть ему определенный тип значения. Более того, с асинхронным и ожидающим, существует больше вариантов, и ваш код будет более переносимым.

По сути, важно понимать плюсы и минусы с «Задачи против streamов» и .NET ThreadPool. Если мне нужна высокая производительность, я собираюсь использовать streamи, и я предпочитаю использовать свой собственный пул.

Простым способом сравнения является запуск 512 streamов, 512 задач и 512 streamов ThreadPool. Вы найдете задержку в начале с Threads (следовательно, зачем писать пул streamов), но все 512 streamов будут выполняться через несколько секунд, в то время как streamи задач и .NET ThreadPool занимают до нескольких минут.

Ниже приведены результаты такого теста (четырехъядерный kernel ​​i5 с 16 ГБ ОЗУ), давая каждые 30 секунд для запуска. Выполненный код выполняет простой ввод / вывод файлов на накопителе SSD.

Результаты теста

Пулы streamов великолепны, когда у вас больше задач для обработки, чем доступных streamов.

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

Проверьте эту страницу в MSDN: http://msdn.microsoft.com/en-us/library/3dasc8as(VS.80).aspx

Всегда используйте пул streamов, если можете, работайте на самом высоком уровне абстракции. Пулы streamов скрывают создание и уничтожение streamов для вас, это, как правило, хорошо!

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

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

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

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

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

Не забудьте исследовать работника фона.

Я нахожусь для многих ситуаций, это дает мне то, что я хочу без тяжелой атлетики.

Приветствия.

Обычно я использую Threadpool всякий раз, когда мне нужно просто что-то делать в другом streamе, и мне все равно, когда он работает или заканчивается. Что-то вроде регистрации или, возможно, даже загрузки фоновым файлом (хотя есть более эффективные способы сделать этот asynchronous стиль). Я использую свой собственный stream, когда мне нужно больше контроля. Также я нашел, что использование очереди Threadsafe (взломать ваш собственный) для хранения «объектов команд» является приятным, когда у меня есть несколько команд, над которыми мне нужно работать в> 1 streamе. Таким образом, вы можете разбить файл Xml и поместить каждый элемент в очередь, а затем задействовать несколько streamов для выполнения некоторой обработки этих элементов. Я написал такую ​​очередь обратно в uni (VB.net!), Которую я преобразовал в C #. Я включил его ниже без особых причин (этот код может содержать некоторые ошибки).

 using System.Collections.Generic; using System.Threading; namespace ThreadSafeQueue { public class ThreadSafeQueue { private Queue _queue; public ThreadSafeQueue() { _queue = new Queue(); } public void EnqueueSafe(T item) { lock ( this ) { _queue.Enqueue(item); if ( _queue.Count >= 1 ) Monitor.Pulse(this); } } public T DequeueSafe() { lock ( this ) { while ( _queue.Count <= 0 ) Monitor.Wait(this); return this.DeEnqueueUnblock(); } } private T DeEnqueueUnblock() { return _queue.Dequeue(); } } } 

Я хотел, чтобы пул streamов распределял работу по ядрам с минимальной задержкой, и это не должно было хорошо работать с другими приложениями. Я обнаружил, что производительность streamа streamов .NET не так хороша, как могла бы быть. Я знал, что мне нужен один stream на kernel, поэтому я написал свой собственный class замены пула streamов. Код предоставляется как ответ на другой вопрос StackOverflow.

Что касается исходного вопроса, пул streamов полезен для разбиения повторяющихся вычислений на части, которые могут выполняться параллельно (предполагая, что они могут выполняться параллельно, не изменяя результат). Ручное управление streamами полезно для таких задач, как UI и IO.

  • Создание пула streamов с использованием boost
  • Именование streamов и streamов-streamов ExecutorService
  • Как настроить тонкую пул streamов для фьючерсов?
  • Что такое эквивалент async / await сервера ThreadPool?
  • Ограничивающие streamи пула streamов C #
  • Пул streamов с использованием boost asio
  • Пул streamов C ++
  • FixedThreadPool против CachedThreadPool: меньшее из двух зол
  • Доступ к областям профилированных объектов в streamах
  • Как Threadpool повторно использует streamи и как это работает
  • C # - ThreadPool vs Tasks
  • Давайте будем гением компьютера.