Эффективное решение для множественного поиска маски по шаблону в 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?

0 ответов

Другие вопросы по тегам