Краткий ответ о том, как улучшить производительность этого кода: Вы не можете.
Реальной производительностью, с которой вы столкнулись, является фактическая задержка диска или сети, поэтому независимо от того, каким образом вы переворачиваете его, вы должны проверять и перебирать каждый элемент файла и извлекать каталоги и списки файлов. (Это, конечно, исключает модификации оборудования или драйверов для уменьшения или улучшения задержки диска, но многим людям уже платят большие деньги за решение этих проблем, поэтому мы пока проигнорируем эту сторону)
Учитывая исходные ограничения, уже опубликовано несколько решений, которые более или менее элегантно оборачивают процесс итерации (однако, поскольку я предполагаю, что я читаю с одного жесткого диска, параллелизм НЕ поможет быстрее проходить каталог дерево, и может даже увеличить это время, поскольку теперь у вас есть два или более потоков, борющихся за данные на разных частях диска, когда он пытается искать и четвертый) уменьшить количество создаваемых объектов и т. д. Однако, если мы оценим, как Функция будет использоваться конечным разработчиком. Мы можем придумать некоторые оптимизации и обобщения.
Во-первых, мы можем задержать выполнение производительности, возвращая IEnumerable, yield return выполняет это, компилируя в перечислителе конечного автомата внутри анонимного класса, который реализует IEnumerable, и возвращается при выполнении метода. Большинство методов в LINQ написаны так, чтобы задерживать выполнение до тех пор, пока не будет выполнена итерация, поэтому код в select или SelectMany не будет выполняться до тех пор, пока IEnumerable не будет повторен. Конечный результат отложенного выполнения ощущается только в том случае, если вам нужно взять подмножество данных позднее, например, если вам нужны только первые 10 результатов, задержка выполнения запроса, который возвращает несколько тысяч результатов, не будет повторяйте все 1000 результатов, пока вам не понадобится больше десяти.
Теперь, учитывая, что вы хотите выполнить поиск по подпапкам, я также могу сделать вывод, что это может быть полезно, если вы можете указать эту глубину, и если я сделаю это, это также обобщит мою проблему, но также потребует рекурсивного решения. Затем, позже, когда кто-то решит, что теперь ему нужно искать в двух каталогах, потому что мы увеличили количество файлов и решили добавить еще один уровень категоризации , вы можете просто сделать небольшую модификацию вместо переписывания функция.
В свете всего этого, вот решение, которое я придумал, которое дает более общее решение, чем некоторые другие, перечисленные выше:
public static IEnumerable<FileInfo> BetterFileList(string fileSearchPattern, string rootFolderPath)
{
return BetterFileList(fileSearchPattern, new DirectoryInfo(rootFolderPath), 1);
}
public static IEnumerable<FileInfo> BetterFileList(string fileSearchPattern, DirectoryInfo directory, int depth)
{
return depth == 0
? directory.GetFiles(fileSearchPattern, SearchOption.TopDirectoryOnly)
: directory.GetFiles(fileSearchPattern, SearchOption.TopDirectoryOnly).Concat(
directory.GetDirectories().SelectMany(x => BetterFileList(fileSearchPattern, x, depth - 1)));
}
Кстати, еще кое-что, о чем никто не упоминал, - это права доступа к файлам и безопасность. В настоящее время нет запросов на проверку, обработку или разрешения, и код будет выдавать исключения разрешений для файлов, если он обнаружит каталог, к которому у него нет доступа для перебора.