我正在创建 msbuild 项目,其中一项任务是在满足提供的任何文件掩码的目录中查找所有文件。
我意识到,即使我在/属性中只创建了Item
带有多个通配符的一行,msbuild 也会为每个通配符完全重新扫描整个目录层次结构。Include
Exclude
因此,如果完整目录扫描($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 目录以“预热”FS 并将它可以缓存的任何内容,然后它查找单个掩码,然后查找两个掩码(一个包含和一个排除),然后查找五个掩码(两个包含和 3 个排除) .
当我使用/v:diag
switch 运行它时,我收到以下时间:
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
which 表明 msbuild 确实在同一文件层次结构上一一搜索所有掩码。
一般来说,我正在寻找什么 - 如何使CheckFive
目标与任务或多或少地花费相同的时间CheckOne
。
为了证明自己枚举文件很慢,我创建了自定义任务,它仅枚举目录层次结构,并对每个文件应用多个掩码 - 是的,任何合理数量的掩码都需要或多或少相同的时间。
但我仍然认为我做错了什么——我可以用纯 msbuild 达到同样的效率吗?