如何加快aspnet_compiler.exe的速度?

mar*_*ark 0 c# asp.net aspnet-compiler

我们有 Asp.Net Mvc 应用程序,aspnet_compiler.exe 的运行时间超过 5 分钟。

Asp.Net Mvc 应用程序依赖于大约 100 个较小的项目,这些项目都通过从自己的项目文件夹中复制它们来为其提供不同的静态视图、Javascript 文件等。这些小项目本身不是 Web 应用程序,但它们包含 Web 内容以便在不同项目之间分发它。

最后,所有内容都整合到一个 Web 应用程序中。然后我们运行aspnet_compiler.exe,这需要5分钟多的时间。哎哟。

该代码针对 .Net Framework 4.7.2,并且 Web 应用程序不是 SDK 风格。

我们显然做错了什么。我们怎样才能减少这个时间呢?

编辑1

整个解决方案需要约 14.5 分钟才能使用 msbuild 和/m:12. msbuild节点利用率不好。根据详细的构建摘要,它是:

============================== Node Utilization (IDs represent configurations) ====================================================
Timestamp:            1       2       3       4       5       6       7       8       9       10      11      12       Duration   Cumulative
...
Utilization:          22.8    11.7    17.2    7.2     52.4    16.6    12.8    13.3    13.1    29.8    34.3    14.9     Average Utilization: 20.5104451261997
Run Code Online (Sandbox Code Playgroud)

我认为利用率低下是由于 aspnet_compiler 在构建过程中被调用得相对较晚,此时所有剩余项目都依赖于主 Web 应用程序来完成构建。我已将项目构建事件捕获为 chrome 跟踪(受到https://github.com/rainersigwald/TraceEventLogger 的启发),这是鸟瞰图: 在此输入图像描述

中间看起来像一座长桥的是主 Web 应用程序的构建事件。构建需要8 分 55分钟,其中AspNetCompiler任务需要5 分 15分钟。

所以我试图理解为什么需要这么长时间?我还在探索其他可能性,例如将其安排为独立项目,以便 msbuild 可以根据主 Web 应用程序将其与项目并行排队。但主要问题仍然存在 - 可以对 Asp.Net 视图预编译做些什么来使其运行得更快。

不幸的是,它对我来说是一个盒子。我真的不知道它是如何工作的以及优化它的方法是什么。

use*_*740 7

aspnet_compiler 速度很,并且内部不允许/支持并行编译。它从未针对性能或基本并行编译进行更新,并且在这一点上是“遗留垃圾”。也不可能在同一站点上同时运行多个实例。由于 aspnet_compiler 会生成许多临时文件,因此使用更快的驱动器可能会有所帮助:但是,即使使用最快的 SSD,CPU 的利用率也明显不足。

使用 Roslyn可以将编译速度比 .NET Framework 提供的编译器提高 2 倍以上,这是我发现提高“核心”编译性能的唯一方法。由于编译速度更快,它还提高了站点预热速度。

使用 Roslyn 1时的轶事性能,

  • MSBuild 在约 5 分钟内编译“200 个程序集”
  • aspnet_compiler 在 ~40m 内编译网站(在 Roslyn 之前约为 100m

我强烈建议使用 Rosyln,即使这不会使网站编译“快速”;它还允许从视图和 ASPX 文件访问 C#7 功能。确保 Rosyln 正确使用 VBCSCompiler.exe 服务模型。

假设没有需要挖掘的编译错误,将 IIS 站点编译一次而不是为站点中的每个应用程序编译一次会更高效。

对于 CI/CD 管道,如果可能,请使用发布版本。同时拥有发布版本发布 web.config 设置(即debug="false"可以加快编译速度。将发布 web.config 设置与调试版本一起使用时,结果似乎更加复杂。YMMV。

使用发布与调试版本时的轶事性能,

  • 用于调试的 CI/CD 服务器构建时间约为 35m
  • CI/CD 服务器构建将在约 25 分钟内发布

对于本地开发,如果可能,请使用就地编译。就地编译允许选择增量编译默认情况下仅重新编译修改过的文件

使用就地编译进行本地开发时的轶事性能,

  • 第一次编译在 ~40m 内完成
  • 第二次编译,大约 10 秒内没有更改任何文件

增量就地编译可能会导致一些错误,例如库中的 ABI 是否损坏;完全重新编译(-c选项)将解决该问题。CI/CD 构建可能应该始终执行完整编译。

将“JScript”文件更新为 C#/VB.NET

Roslyn 和 CodeDom 都不适用于这种遗留语言,并且此类页面的出现必须通过一些旧的编译器过程来运行,该过程要慢得多。

不幸的是,aspnet_compiler 还缺乏足够的输出生成来确定站点的哪些部分花费最多时间进行编译。


1我正在处理的网站当前有 189 个已编译的程序集、97 个 .INC 和 .ASP 经典文件、1580 个 .ASPX 文件(C# WebForms 和“脚本”的混合)以及 1221 个 .CSHTML 文件。IIS 中的最终 .COMPILED 文件计数为 5788。性能改进可能会因多种因素而异,包括文件类型和依赖关系图。


Cliff 关于为 aspnet_compiler 设置 Roslyn 的说明:

  • 下载 Rosyln CodeDom 包 ( Microsoft.CodeDom.Providers.DotNetCompilerPlatform )。这包括 CodeDom 和 Roslyn 的构建。

  • 确保包中的 Roslyn 目录以 结尾bin/roslyn,但是这适合构建系统。这里有一个手动预构建复制步骤。同样,CodeDom 桥接程序集必须采用bin/.

  • 更新system.codedom/compilersweb.config 文件中的部分,如示例中所示。如果不使用 VB.NET,则可以删除该编译器条目以及特定于 VB 的 Roslyn 分析器。(请注意,下面我设置/langversion:7了 C#7 功能,这是任何 .NET Framework 目标中官方支持的最高设置。)

    <system.codedom>
        <compilers>
          <compiler language="c#;cs;csharp" extension=".cs"
            type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
            warningLevel="4" compilerOptions="/langversion:7 /nowarn:1659;1699;1701"/>
          <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb"
            type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
            warningLevel="4" compilerOptions="/langversion:14 /nowarn:41008 /define:_MYTYPE=\&quot;Web\&quot; /optionInfer+"/>
        </compilers>
    </system.codedom>
    
    Run Code Online (Sandbox Code Playgroud)

验证 Roslyn 是否被正确调用:

开始网站建设。在编译期间应该启动许多 csc.exe实例。然而,这些可执行实例不应占用太多内存。相反,应该有另一个可执行文件VBCSCompiler.exe从该bin/roslyn目录运行(Visual Studio 也可能生成它自己的 Roslyn 编译服务器)。此可执行文件是 csc.exe 可执行文件向其发送请求的编译服务器。拥有长期运行的编译VBCSCompiler.exe服务器模型对于 Roslyn 的最大性能优势至关重要,因为它避免了编译器本身相对昂贵的持续重生。如果编译服务器无法启动,csc.exe进程将回退到自己进行繁重的编译。