Поиск строк на совпадение в текстовых файлах C#

В общем, другу понадобился софт, который удаленно, на его сервере ищет из всех содержащихся там текстовых файлов совпадение по заданному слову. Я написал класс отвечающий за TCP соединение и вот тут вопрос по классу, который будет искать. В принципе все работает, даже системные ресурсы не так сильно жрет (за исключением процессора до 20%), но все же скорость поиска меня не устаревает, хочется побыстрее. Вот код и вопрос, как можно улучшить, ускорить его работу

foreach (string item in dirWork)
{
    foreach (string item2 in SafeEnumerateFiles(item))
    {
        using (StreamReader _reader = new StreamReader(new BufferedStream(File.OpenRead(item2), 1024 * 1024)))
        {
            string line;
            while ((line = await _reader.ReadLineAsync()) != null)
            {
                if (line.Contains(ItemSearch))
                {
                    name.Add($"{Path.GetFileName(item2)}");
                    result.Add($"{line}");
                }
            }
        }
    }
}

dirWork содержит коллекцию папок лежащие на разных дисках. SafeEnumerateFiles(item) метод возвращает полную коллекцию всех файлов в папке и подпапках.


Ответы (1 шт):

Автор решения: tym32167

Если вам нужна скорость, то я бы вот что попробовал

  1. Убрал бы асинхронность. Асинхронность делает приложение более отзывачивым, но конкретная операция может стать медленней из за построения конечногго автомата и переключений контекста. Но это чисто догадка, я не проверял её правдивость.

  2. Увеличил бы буфер. Один мегабайт таки это маловато. Я бы сделал магабайт 10-100 на поток

  3. Обрабатывал бы файлы параллельно. При большои буфере в одном потоке когда файл считыватся, проц простаивает и когда данные обрабатываются - простаивает жесткий диск.

Вот пример

private IEnumerable<(string filename, string line)> GetFilieredLines(string file, string pattern)
{
    using(var reader = new StreamReader( new BufferedStream( File.OpenRead(file), 10*1024*1024) ))
    {
        while(!reader.EndOfStream)
        {
            var line = reader.ReadLine();
            if(line.Contains(pattern)) yield return (file, line);
        }
    }
}

Как вызывать

var folder = @"D:\.....";
var results = Directory.GetFiles(folder, "*.cs", SearchOption.AllDirectories)
    .AsParallel()
    .SelectMany(x=>GetFilieredLines(x, "public class"))
    .Dump();

Вывод

...

→ Ссылка