Читать и обрабатывать большие текстовые файлы ~ 100 МБ каждый - PullRequest
2 голосов
/ 27 февраля 2012

У меня есть список больших текстовых файлов для обработки. Интересно, какой самый быстрый метод, потому что чтение построчно идет медленно. У меня что-то подобное:

int cnt = this.listView1.Items.Count;

for (int i = 0; i < this.listView1.Items.Count; i++)
{
     FileStream fs = new FileStream(this.listView1.Items[i].Text.ToString(),             FileMode.Open, FileAccess.Read);
     using (StreamReader reader = new StreamReader(fs))
     while (reader.Peek() != -1)
          {
             //code part
          }
}

Я читал об использовании блоков (например, по 100 тыс. Строк) через фоновых рабочих с несколькими потоками, это помогло бы, но я не знаю, как это реализовать. Или, если у вас есть лучшие идеи для улучшения производительности ... ваш совет специалиста был бы оценен.

Ответы [ 3 ]

4 голосов
/ 27 февраля 2012

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

Я согласен с @asawyer, если это всего лишь 100 МБ, вы должны прочитать файл целиком в память одним махом. С таким же успехом вы могли бы прочитать 5 из них полностью в память, это не имеет большого значения.

РЕДАКТИРОВАТЬ: После осознания все файлы находятся на одном жестком диске, и эта обработка занимает больше времени, чем чтение файла.

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

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

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

2 голосов
/ 28 февраля 2012

Я предполагаю, что вы обрабатываете файлы построчно. Вы также сказали, что загрузка файлов происходит быстрее, чем их обработка. Есть несколько способов сделать то, что вам нужно. Один например:

Создать поток, который читает файлы один за другим, строка за строкой. Последовательно, потому что при параллельном выполнении этой операции вы только забьете свой жесткий диск и, возможно, получите худшие результаты. Вы можете использовать Queue<string> для этого. Используйте Queue.Enqueue(), чтобы добавить красные линии.

Запустить другой поток, который обрабатывает очередь. Используйте Queue.Dequeue(), чтобы получить (и удалить) строки из начала вашей очереди. Обработайте строку и запишите ее в выходной файл. В конце концов, вы можете поместить обработанные строки в другую очередь или список и записать их сразу после завершения обработки.

Если порядок строк в выходном файле не важен, вы можете создать столько потоков, сколько у вас ядер ЦП (или использовать класс ThreadPool) для выполнения обработки (что значительно ускорит процесс).

[Изменить] Если порядок строк в выходном файле важен, вам следует ограничить обработку строк одним потоком. Или обрабатывайте их параллельно, используя отдельные потоки, и реализуйте механизм, который будет контролировать порядок вывода. Например, вы можете сделать это путем нумерации строк, которые вы читаете из входного файла (простой способ), или обработки строк каждым потоком в виде фрагментов из n-строк и записи выходного фрагмента по фрагменту в том же порядке, в котором вы начали обработку потоков.

0 голосов
/ 27 февраля 2012

вот простой код многопоточности, который вы можете использовать: (.Net 4)

//firstly get file paths from listview so you won't block the UI thread
List<string> filesPaths = new List<string>();

for (int i = 0; i < this.listView1.Items.Count; i++)
{
     filesPaths.Add(listView1.Items[i].Text.ToString());
}


//this foreach loop will fire 50 threads at same time to read 50 files
Parallel.ForEach(filesPaths, new ParallelOptions() { MaxDegreeOfParallelism = 50 }, (filepath, i, j) =>
{    
     //read file contents
     string data = File.ReadAllText(filepath);

     //do whatever you want with the contents

}); 

не проверено, хотя ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...