正则表达式中的编译和重复使用
通过了解正则表达式引擎编译表达式的方式以及正则表达式的缓存方式,可以优化大量使用正则表达式的应用程序的性能。 本文讨论已编译的正则表达式的编译、源生成和缓存。
解释的正则表达式
默认情况下,正则表达式引擎将正则表达式编译成内部指令序列(这些指令序列是不同于公共中间语言 (CIL) 的高级代码)。 当引擎执行正则表达式时,会解释内部代码。
已编译的正则表达式
如果 Regex 对象是通过 RegexOptions.Compiled 选项构造而成,它会将正则表达式编译为显式 CIL 代码,而不是高级正则表达式内部指令。 这样,.NET 的实时 (JIT) 编译器便可以将表达式转换为本机代码以获得更高的性能。 构造 Regex 对象的成本可能会更高,但执行其匹配项的开销可能会小得多。
源生成的正则表达式
正则表达式的源生成在 .NET 7 及更高版本中可用。 源生成器以 C# 代码的形式发出自定义 Regex
派生实现,其逻辑类似于 IL 中 RegexOptions.Compiled
发出的内容。 可以获得 RegexOptions.Compiled
的所有吞吐量性能优势和 Regex.CompileToAssembly
的启动优势,但没有 CompileToAssembly
的复杂性。 发出的源是项目的一部分,这意味着它也可以轻松查看和调试。
请尽可能地使用源生成的正则表达式,而不是使用 RegexOptions.Compiled 选项编译正则表达式。 有关源生成的正则表达式的详细信息,请参阅 .NET 正则表达式源生成器。
正则表达式缓存
为了提高性能,正则表达式引擎为已编译的正则表达式维护了一个应用程序范围的缓存。 该缓存只存储静态方法调用中使用的正则表达式模式。 (不缓存提供给实例方法的正则表达式模式。)缓存避免了每次使用表达式时都需要将其重新分析成高级字节代码。
缓存正则表达式数上限由 static
(Visual Basic 中的 Shared
)Regex.CacheSize 属性的值决定。 默认情况下,正则表达式引擎最多可缓存 15 个已编译的正则表达式。 如果已编译正则表达式的数目超过缓存大小,则丢弃最早使用的正则表达式并缓存新的正则表达式。
应用程序可通过以下两种方式之一来重用正则表达式:
- 使用 Regex 对象的静态方法定义正则表达式。 如果要使用的正则表达式模式已由其他静态方法调用定义,则正则表达式引擎将尝试从缓存中检索该模式。 如果它在缓存中不可用,则引擎将编译正则表达式并将其添加到缓存中。
- 重用现有 Regex 对象(只要需要使用正则表达式模式)。
鉴于对象实例化和正则表达式编译产生的开销,因此创建并迅速销毁大量 Regex 对象的进程成本很高。 对于使用大量不同正则表达式的应用,可以调用静态方法 Regex
,并尽量增加正则表达式缓存大小,从而优化性能。