#c# #.net #multithreading
#c# #.net #многопоточность
Вопрос:
У меня есть следующий код:
if (!this.writeDataStore.Exists(mat))
{
BlockingCollection<ImageFile> imageFiles = new BlockingCollection<ImageFile>();
Parallel.ForEach(fileGrouping, fi => DecompressAndReadGzFile(fi, imageFiles));
this.PushIntoDb(mat, imageFiles.ToList());
}
DecompressAndReadGzFile
является статическим методом в том же классе, в котором содержится этот метод. Согласно названию метода, я распаковываю и считываю gz-файлы, их много, то есть до 1000, так что издержки распараллеливания окупаются за счет преимуществ. Однако я не вижу преимуществ. Когда я использую ANTS performance profiler, я вижу, что они выполняются точно в то же время, как если бы никакого распараллеливания не происходило. Я также проверяю ядра процессора с помощью process Explorer, и похоже, что, возможно, работа выполняется на двух ядрах, но одно ядро, похоже, выполняет большую часть работы. Чего я не понимаю в плане получения параллельного.Использовать каждый для распаковки и чтения файлов параллельно?
ОБНОВЛЕННЫЙ ВОПРОС: Какой самый быстрый способ считывать информацию из списка файлов?
Проблема (упрощенная):
- Существует большой список файлов .gz (1200).
- В каждом файле есть строка, содержащая «DATA: «, расположение и номер строки не являются статическими и могут варьироваться от файла к файлу.
- Нам нужно извлечь первое число после «DATA:» (просто для простоты) и сохранить его в объекте в памяти (например, в списке)
В первоначальном вопросе я использовал параллельный.Цикл ForEach, но я, похоже, не привязан к процессору более чем на 1 ядре.
Комментарии:
1. Выполняется ли какая-либо синхронизация в
DecompressAndReadGzFile
?2. Насколько мне известно, нет. Хотя есть вызов imageFiles. Добавить, который автоматически добавляет блокировку, насколько я понимаю.
Ответ №1:
Возможно ли, что потоки тратят большую часть своего времени на ожидание ввода-вывода? Читая несколько файлов одновременно, вы можете увеличить нагрузку на диск, чем при выполнении одной операции. Возможно, вы могли бы повысить производительность, используя последовательное чтение одним потоком, но затем распределяя декомпрессию с привязкой к процессору по отдельным потокам… но на самом деле вы можете обнаружить, что вам действительно нужен только один поток, выполняющий декомпрессию в любом случае, если диск работает медленнее, чем сам процесс декомпрессии.
Одним из способов проверить это было бы сначала скопировать файлы, требующие распаковки, на ramdisk и по-прежнему использовать ваш текущий код. Я подозреваю, что затем вы обнаружите, что привязаны к процессору, и все процессоры заняты почти все время.
(Вам также следует подумать о том, что вы делаете с распакованными файлами. Вы записываете их обратно на диск? Если это так, опять же, есть вероятность, что вы в основном ожидаете, что диск будет перегружен.)
Комментарии:
1. Я не записываю распакованные файлы на диск. Я считываю файлы сжатия в память с помощью GZipStream, создаю TextReader для извлечения того, что мне нужно, помещая это в коллекцию imageFiles в приведенном выше коде. Я мог бы попробовать ваше предложение по RAM-диску.
2. @Seth: Обратите внимание, что предложение ramdisk на самом деле просто предназначено для проверки того, что вы привязаны к вводу-выводу, а не к процессору. Если это так, то в конечном итоге вы просто перенесете затраты на этап «копирование данных на ramdisk».
3. Помните те драйверы программного обеспечения turbo Booster для жестких дисков много лет назад? Они ускорили дисковый ввод-вывод, сжимая данные в памяти, а затем записывая сжатые данные на диск.
Ответ №2:
есть ли вероятность, что ваш статический метод совместно использует какой-либо глобальный ресурс среди своих вызовов. Потому что в этом случае этот статический метод будет вызываться последовательно и никакой параллельной выгоды. Можете ли вы поместить код класса fileGrouping?