Эффективное решение для множественного поиска маски по шаблону в msbuild?
Я создаю проект msbuild, и одна из задач состоит в том, чтобы найти все файлы в каталогах, которые удовлетворяют любой из предоставленных масок файлов.
Я понял, что даже если я создаю только одну строку Item
с несколькими подстановочными знаками в Include
/ Exclude
Атрибуты msbuild полностью повторно сканирует всю иерархию каталогов для каждого из этих подстановочных знаков.
Так что, если полное сканирование каталога, как ($Path)\**
занимает, скажем, 6 секунд, а затем использование только 10 символов подстановки сделает его одной минутой - что довольно медленно для моих целей.
Я полагаю, что сканирование файлов - это действительно медленная операция, в то время как сравнение масок (одна, десятка или тысяча на имя файла) должно быть в несколько раз быстрее - поэтому я ищу решение, которое эффективно сканирует иерархию каталогов для нескольких масок файлов.
Вот пример проекта msbuild, который показывает, что я имею в виду:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<PropertyGroup>
<MyPath>C:\Windows</MyPath>
</PropertyGroup>
<Target Name="Build" DependsOnTargets="Warmup;CheckOne;CheckTwo;CheckFive">
</Target>
<Target Name="Warmup">
<ItemGroup>
<Item1 Include="$(MyPath)\**" />
</ItemGroup>
</Target>
<Target Name="CheckOne">
<ItemGroup>
<Item2 Include="$(MyPath)\**\*.exe" />
</ItemGroup>
</Target>
<Target Name="CheckTwo">
<ItemGroup>
<Item2 Include="$(MyPath)\**\*.dll" Exclude="$(MyPath)\**\System32\**" />
</ItemGroup>
</Target>
<Target Name="CheckFive">
<ItemGroup>
<Item3 Include="$(MyPath)\**\*.exe;$(MyPath)\**\*.dll" Exclude="$(MyPath)\**\System32\**;$(MyPath)\**\SysWOW64\**;$(MyPath)\**\winsxs\**" />
</ItemGroup>
</Target>
</Project>
Сначала он сканирует полный каталог Windows, чтобы "прогреть" ФС и поместить все, что может, в кеш, затем ищет одну маску, затем две маски (одну включают и одну исключают), затем пять масок (две включают и 3 исключают).,
Когда я запускаю его с /v:diag
Переключатель я получаю следующие тайминги:
Target Performance Summary:
0 ms Build 1 calls
6196 ms CheckOne 1 calls
7942 ms Warmup 1 calls
15030 ms CheckTwo 1 calls
39249 ms CheckFive 1 calls
Так что я вижу, что в среднем каждая маска добавляет 6-8 секунд к результатам.
Подобные результаты можно увидеть, например, используя procmon
что показывает, что msbuild действительно ищет все маски по одной в одной и той же файловой иерархии.
В общем что я ищу - как сделать CheckFive
цель принять более или менее в то же время, что и CheckOne
задача.
Чтобы доказать, что перечисление файлов выполняется медленно, я создал пользовательское задание, которое перечисляет только одну иерархию каталогов и применяет к каждому файлу несколько масок - и да, для любого разумного количества масок требуется более или менее одинаковое время.
Но я все еще думаю, что делаю что-то не так - могу ли я добиться такой же эффективности с чистым msbuild?