2010-08-04 3 views
6

Я создал приложение, которое выполняет работу над тысячами файлов, а затем записывает измененные копии этих файлов на диск. Я использую ThreadPool, но он породил столько потоков, что ПК становился невосприимчивым к 260), поэтому я изменил максимальный размер от 250 до 50, это решило эту проблему (приложение только порождает около 60 потоков), однако теперь, когда файлы становятся такими быстрыми, привязка интерфейса к точке, где ПК не отвечает.Могу ли я ограничить ввод/вывод моего приложения C#

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

+1

Вы говорите: «Файлы становятся настолько быстрыми, что связывают пользовательский интерфейс». Обновляется ли пользовательский интерфейс каждый раз, когда файл готов? Если это так, может быть, это реальная проблема здесь? –

ответ

7

Использование семафора для ограничения нет. потоков, которые хотят записывать на диск одновременно.

http://msdn.microsoft.com/en-us/library/system.threading.semaphore.aspx

ограничивает число потоков, которые могут доступ к ресурсу или пул ресурсов одновременно.

+0

Awesome, thanks – schmoopy

4

Вам действительно не нужно столько потоков. Диск может поддерживать только максимальную пропускную способность чтения и записи, которая может быть легко отключена одним потоком, если она посвящена IO, то есть чтению или записи. Вы также не можете читать и записывать на жесткий диск одновременно (хотя это сложно с уровнями кэширования ОС и т. Д.), Поэтому одновременное чтение и запись потоков могут быть очень контрпродуктивными. Существует также мало того, что можно получить больше потоков, чем процессоры \ ядра для ваших задач, отличных от IO, поскольку любые дополнительные потоки будут тратить большую часть своего времени, ожидая, когда ядро ​​станет доступным, например. если у вас есть 50 нитей и 4 ядра, минимум 46 потоков будут простаивать в любой момент времени. Пропущенные потоки будут способствовать как потреблению памяти, так и повлечь за собой накладные расходы, поскольку все они будут бороться, чтобы получить трещины в какое-то время на ядре, и ОС должна разрешить этот бой.

Более простой подход должен состоять из одного потока, задание которого должно считываться в файлах, а затем добавлять данные в очередь блокировки (например, см. ConcurrentQueue), между тем есть ряд рабочих потоков, которые ждут файлов в очереди (например, число потоков, равное числу процессоров \ ядер). Эти рабочие потоки будут пробиваться через очередь по мере добавления элементов и блокировать их, когда они пусты. Когда рабочий поток завершает часть работы, он может добавить это в другую блокирующую очередь, которая контролируется либо потоком считывателя, либо выделенным потоком писателя. Его задача - записать файлы.

Этот шаблон предназначен для балансировки IO и CPU среди гораздо меньшего количества взаимодействующих потоков, где количество потоков ввода-вывода ограничено физически способным жестким диском и количеством рабочих потоков ЦП, разумный для количества процессоров \ ядер, которые у вас есть. По сути, он отделяет работу ввода-вывода и ЦП, так что вещи ведут себя более предсказуемо.

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

Update

Может быть, стоит объяснить, почему существует так много потоков генерируется в первую очередь. Это дегенеративный случай использования threadpool и сосредоточен вокруг рабочих очередей, которые имеют компонент IO в них.

Пул threadpool выполняет рабочие элементы из своей очереди и контролирует, как долго выполняются рабочие элементы. Если в настоящее время выполнение рабочих элементов занимает много времени (я думаю, полторы секунды из памяти), то он начнет добавлять больше потоков в пул, так как считает, что это приведет к более быстрой обработке очереди. Однако, если дополнительные одновременные рабочие элементы также выполняют IO работы с общим диском, производительность диска фактически уменьшится, а это означает, что рабочие элементы будут занимать еще больше времени. Поскольку workitems занимают больше времени для выполнения, threadpool добавляет больше потоков. Это дегенеративный случай, когда производительность становится все хуже и хуже по мере добавления новых потоков.

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

+0

ThreadPool выполняет сложные вычисления на основе содержимого каждого файла, а использование ThreadPool ускоряет эту часть процесса. LOTS :-) – schmoopy

+0

@schmoopy Я не уверен, что понимаю ваш комментарий. Я знаком с threadpool и обработкой файлов, поэтому я ответил на ваш вопрос. В деталях я мог бы добавить ... –

Смежные вопросы