<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Performance | The .NET Blog</title><link>https://thedotnetblog.com/zh/tags/performance/</link><description>Articles, tutorials and insights from the .NET community.</description><generator>Hugo</generator><language>zh</language><managingEditor>@thedotnetblog (The .NET Blog)</managingEditor><webMaster>@thedotnetblog</webMaster><lastBuildDate>Tue, 26 May 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://thedotnetblog.com/zh/tags/performance/index.xml" rel="self" type="application/rss+xml"/><item><title>.NET 11 终于修复了进程 API</title><link>https://thedotnetblog.com/zh/news/emiliano-montesdeoca/dotnet-11-process-api-improvements-runandcapturetext/</link><pubDate>Tue, 26 May 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/news/emiliano-montesdeoca/dotnet-11-process-api-improvements-runandcapturetext/</guid><description>System.Diagnostics.Process 迎来了多年来最大的更新。RunAndCaptureTextAsync、KillOnParentExit、SafeProcessHandle API，以及对标准句柄重定向的完全控制 — 再也不需要死锁样板代码了。</description><content:encoded>&lt;p&gt;每个曾经需要启动进程并捕获其输出的 .NET 开发者都写过某种变体的危险样板代码：异步读取 stdout、异步读取 stderr、&lt;code&gt;WaitForExitAsync&lt;/code&gt;，不要忘记排空两个流，否则会死锁。这是一个众所周知的陷阱，已经存在多年了。&lt;/p&gt;
&lt;p&gt;.NET 11 终于正确地解决了这个问题。&lt;/p&gt;
&lt;h2 id="runandcapturetextasync"&gt;RunAndCaptureTextAsync&lt;/h2&gt;
&lt;p&gt;核心新增：一个单一的静态方法，可以启动进程、捕获 stdout 和 stderr，并等待退出而不会死锁。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RunAndCaptureTextAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;dotnet&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;--version&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StandardOutput&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;一次调用。无需手动排空流。无需精心放置的 &lt;code&gt;WaitForExit&lt;/code&gt;。如果你只需要运行某个命令并获取其输出，这就是你想要的 API。&lt;/p&gt;
&lt;p&gt;对于想要等待退出但不捕获输出的情况，还有 &lt;code&gt;Process.RunAsync&lt;/code&gt;。&lt;/p&gt;
&lt;h2 id="killonparentexit"&gt;KillOnParentExit&lt;/h2&gt;
&lt;p&gt;已启动进程的常见问题：如果父进程崩溃或被终止，子进程会作为孤儿继续运行。&lt;code&gt;KillOnParentExit&lt;/code&gt; 允许你在进程启动时声明，当父进程退出时子进程也应该被终止。&lt;/p&gt;
&lt;p&gt;这个功能以平台特定的方式存在过（Windows 上的 job objects，Linux 上的 prctl），但需要 p/invoke 或第三方库才能在 .NET 中使用。现在它是 &lt;code&gt;ProcessStartInfo&lt;/code&gt; 上的一等公民属性。&lt;/p&gt;
&lt;h2 id="基于-safeprocesshandle-的-api"&gt;基于 SafeProcessHandle 的 API&lt;/h2&gt;
&lt;p&gt;新的轻量级 API 表面是围绕 &lt;code&gt;SafeProcessHandle&lt;/code&gt; 而不是完整的 &lt;code&gt;Process&lt;/code&gt; 类构建的。完整的 &lt;code&gt;Process&lt;/code&gt; 类携带大量状态，难以裁剪 — &lt;code&gt;SafeProcessHandle&lt;/code&gt; 路径对于需要最小化输出大小的应用程序（WASM、原生 AOT）更加友好。&lt;/p&gt;
&lt;h2 id="对句柄继承的完全控制"&gt;对句柄继承的完全控制&lt;/h2&gt;
&lt;p&gt;此次更新还添加了对子进程继承哪些句柄以及如何重定向标准句柄的精细控制。以前你可以重定向 stdin/stdout/stderr，但无法在 OS 层面精确指定要继承哪些句柄。新 API 暴露了这种控制。&lt;/p&gt;
&lt;h2 id="为何重要"&gt;为何重要&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Process&lt;/code&gt; 类用于工具、构建系统、测试运行器以及任何调用其他可执行文件的应用程序。旧的 API 表面可以追溯到 .NET Framework，已经显示出老化的迹象。这不是破坏性变更 — 旧 API 仍然有效 — 但新代码应该优先使用新表面。&lt;/p&gt;
&lt;p&gt;对于裁剪的应用程序或 AOT 编译场景，&lt;code&gt;SafeProcessHandle&lt;/code&gt; 路径特别受欢迎。旧的 &lt;code&gt;Process&lt;/code&gt; 类带来了大量反射繁重的代码，使得裁剪变得复杂。&lt;/p&gt;
&lt;p&gt;原文链接：&lt;a href="https://devblogs.microsoft.com/dotnet/process-api-improvements-in-dotnet-11/"&gt;Process API Improvements in .NET 11&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>Copilot Studio 如何迁移到 .NET 10 WebAssembly 并提速 20%</title><link>https://thedotnetblog.com/zh/news/emiliano-montesdeoca/copilot-studio-net10-webassembly-migration-performance/</link><pubDate>Sat, 23 May 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/news/emiliano-montesdeoca/copilot-studio-net10-webassembly-migration-performance/</guid><description>.NET 10 WASM 的改进不仅仅适用于新项目。以下是 Copilot Studio 从 .NET 8 升级后测量到的结果：自动指纹识别、默认启用 WasmStripILAfterAOT 以及真实的执行性能数据。</description><content:encoded>&lt;p&gt;Copilot Studio 团队做了所有 Blazor WASM 开发者都好奇的事情：他们实际上将一个生产应用程序从 .NET 8 升级到了 .NET 10 并测量了结果。这篇文章分享了具体数字，这很罕见也非常有用。&lt;/p&gt;
&lt;h2 id="升级过程很无聊这是好事"&gt;升级过程很无聊（这是好事）&lt;/h2&gt;
&lt;p&gt;更新目标框架、刷新包引用、修复破坏性更改。就这样。.NET 10 构建现在已在生产环境中运行。迁移本身并不是有趣的部分——.NET 10 中的变化才是。&lt;/p&gt;
&lt;h2 id="自动资源指纹识别"&gt;自动资源指纹识别&lt;/h2&gt;
&lt;p&gt;以前，部署 WASM 应用意味着需要编写自定义脚本来用 SHA256 哈希重命名已发布的资源以进行缓存清除。Copilot Studio 有一个 PowerShell 脚本做的正是这件事——重命名文件、将 &lt;code&gt;integrity&lt;/code&gt; 属性注入 JavaScript 加载器、手动管理一切。&lt;/p&gt;
&lt;p&gt;在 .NET 10 中，所有这些都是内置的。已发布的资源会自动添加指纹，直接从 &lt;code&gt;dotnet.js&lt;/code&gt; 导入，并在无需手动干预的情况下进行完整性验证。团队删除了重命名脚本。&lt;/p&gt;
&lt;p&gt;范围上的小变化，复杂性的显著降低。&lt;/p&gt;
&lt;h2 id="wasmstripilafteraot-现在默认启用"&gt;WasmStripILAfterAOT 现在默认启用&lt;/h2&gt;
&lt;p&gt;在 .NET 8 中，从 AOT 编译的程序集中删除 IL 是选择性的。在 .NET 10 中这是默认行为。AOT 编译后，原始 IL 字节码从输出中删除——运行时不需要它，保留它会无故膨胀包大小。&lt;/p&gt;
&lt;p&gt;Copilot Studio 使用了一种特定的优化：它同时提供 JIT 引擎（快速启动）和 AOT 引擎（最大稳态性能），并行加载两者，并在准备好后从 JIT 切换到 AOT。它还会对两个引擎之间相同的文件进行去重。&lt;/p&gt;
&lt;p&gt;新的 IL 剥离行为意味着 AOT 程序集不再与其 JIT 对应项逐位匹配，因此去重的文件更少：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;.NET 8：59 个共享文件&lt;/li&gt;
&lt;li&gt;.NET 10：22 个共享文件&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;净结果：AOT 引擎的包大小增加了约 15%。在快速 LAN 上 AOT 下载慢约 6%，在 4G 上慢约 17%。但这一切都在应用程序已经可交互后在后台发生。&lt;/p&gt;
&lt;h2 id="性能数字"&gt;性能数字&lt;/h2&gt;
&lt;p&gt;这是重要的部分：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;首次调用时 &lt;strong&gt;快约 20%&lt;/strong&gt;（冷路径）&lt;/li&gt;
&lt;li&gt;后续调用时 &lt;strong&gt;快约 5%&lt;/strong&gt;（热路径）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;改进在&amp;quot;大型机器人&amp;quot;中最为明显——AOT 编译代码主导的大型复杂代理。对于更简单的工作流，收益较小。&lt;/p&gt;
&lt;h2 id="如果您仍在使用-net-8"&gt;如果您仍在使用 .NET 8&lt;/h2&gt;
&lt;p&gt;迁移过程真的很简单：更新 &lt;code&gt;&amp;lt;TargetFramework&amp;gt;&lt;/code&gt;、刷新包引用、删除任何自定义指纹识别脚本，您将自动从 &lt;code&gt;WasmStripILAfterAOT&lt;/code&gt; 中受益。如果您正在 AOT 编译，预期会有类似的性能提升。&lt;/p&gt;
&lt;p&gt;文章中的一个注意事项：如果您在 &lt;code&gt;WebWorker&lt;/code&gt; 中加载 .NET WASM 运行时，请在初始化时设置 &lt;code&gt;dotnetSidecar = true&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;原文：&lt;a href="https://devblogs.microsoft.com/dotnet/copilot-studio-dotnet-10-migration/"&gt;Copilot Studio gets faster with .NET 10 on WebAssembly&lt;/a&gt;&lt;/p&gt;</content:encoded></item></channel></rss>