Поскольку любопытно, как .NET 4 работает с этим в комментариях, вот такой подход. Извините, это скорее всего не вариант для ОП. Отказ от ответственности: это не очень научный анализ, просто показывающий, что есть явное преимущество в производительности. В зависимости от оборудования, ваш пробег может варьироваться в широких пределах.
Вот быстрый тест (если вы видите большую ошибку в этом простом тесте, это всего лишь пример. Пожалуйста, прокомментируйте, и мы можем исправить его, чтобы он был более полезным / точным). Для этого я просто поместил 12 000 ~ 60 КБ файлов в каталог в качестве образца (запустите LINQPad ; вы можете поиграть с ним самостоятельно, бесплатно! - не забудьте получить LINQPad 4, хотя ):
var files =
Directory.GetFiles("C:\\temp", "*.*", SearchOption.AllDirectories).ToList();
var sw = Stopwatch.StartNew(); //start timer
files.ForEach(f => File.ReadAllBytes(f).GetHashCode()); //do work - serial
sw.Stop(); //stop
sw.ElapsedMilliseconds.Dump("Run MS - Serial"); //display the duration
sw.Restart();
files.AsParallel().ForAll(f => File.ReadAllBytes(f).GetHashCode()); //parallel
sw.Stop();
sw.ElapsedMilliseconds.Dump("Run MS - Parallel");
Незначительное изменение цикла для распараллеливания запроса - это все, что нужно для
большинство простые ситуации . Под «простым» я в основном подразумеваю, что результат одного действия не влияет на следующее. Чаще всего следует помнить, что некоторые коллекции, например, наша удобная List<T>
, не безопасна для потоков , поэтому использование ее в параллельном сценарии это хорошая идея :) К счастью, в .NET 4 были добавлены одновременные коллекции, которые являются поточно-ориентированными. Также имейте в виду, что если вы используете блокирующую коллекцию, это может быть узким местом, в зависимости от ситуации.
Используются расширения .AsParallel<T>(IEnumeable<T>)
и .ForAll<T>(ParallelQuery<T>)
, доступные в .NET 4.0. Вызов .AsParallel()
включает IEnumerable<T>
в ParallelEnumerableWrapper<T>
(внутренний класс), который реализует ParallelQuery<T>
. Теперь это позволяет вам использовать методы параллельного расширения , в данном случае мы используем .ForAll()
.
.ForAll()
внутренне создает ForAllOperator<T>(query, action)
и запускает его синхронно. Это обрабатывает многопоточность и объединение потоков после того, как они запущены ... Там довольно много происходит, я бы предложил начинать здесь, если вы хотите узнать больше, включая дополнительные опции .
Результаты (Компьютер 1 - Физический жесткий диск):
- Серийный номер: 1288 - 1333мс
- Параллельно: 461 - 503 мс
Характеристики компьютера - для сравнения:
Результаты (Компьютер 2 - Твердотельный накопитель):
- Серийный номер: 545 - 601 мс
- Параллельно: 248 - 278 мс
Характеристики компьютера - для сравнения:
- Quad Core 2 Quad Q9100 @ 2,26 ГГц
- 8 ГБ ОЗУ (DDR 1333)
- 120 ГБ OCZ Vertex SSD (Стандартная версия - прошивка 1.4)
На этот раз у меня нет ссылок на ЦП / ОЗУ, они были установлены. Это ноутбук Dell M6400 ( вот ссылка на M6500 ... собственные ссылки Dell на на 6400 не работают ).
Эти числа взяты из 10 прогонов, принимая мин / макс внутренних 8 результатов (удаляя исходные мин / макс для каждого возможного выброса). Здесь мы сталкиваемся с узким местом ввода / вывода, особенно на физическом диске, но подумайте о том, что делает последовательный метод. Он читает, обрабатывает, читает, обрабатывает, промыть, повторить. При параллельном подходе вы (даже с узким местом ввода / вывода) считываете и обрабатываете одновременно . В худшем случае вы обрабатываете один файл, а читаете следующий. Одно это (на любом текущем компьютере!) Должно привести к увеличению производительности * . Вы можете видеть, что в приведенных выше результатах мы можем получить чуть больше, чем один раз, давая нам здоровый импульс.
Еще один отказ от ответственности: Quad Core + .NET 4 параллель не даст вам четырехкратного увеличения производительности, он не масштабируется линейно ... Есть и другие соображения и узкие места в игре.
Надеюсь, это было интересно показать подход и возможные выгоды. Не стесняйтесь критиковать или улучшать ... Этот ответ существует только для любопытных, как указано в комментариях:)