0

0

c# Expression.Compile() 的性能开销和并发缓存

幻夢星雲

幻夢星雲

发布时间:2026-01-22 12:53:03

|

531人浏览过

|

来源于php中文网

原创

Expression.Compile() 不应频繁调用,因其每次都会触发IL生成、JIT编译和委托创建,导致高CPU、GC压力及内存泄漏;正确做法是通过结构化key在ConcurrentDictionary或IMemoryCache中缓存编译结果。

c# expression.compile() 的性能开销和并发缓存

Expression.Compile() 为什么不能每次都调用

每次调用 Expression.Compile() 都会触发 IL 生成、JIT 编译和委托创建,底层涉及 DynamicMethodAssemblyBuilder(.NET Core/5+ 默认走 DynamicMethod),实际开销远高于普通方法调用。在高并发场景下,反复编译同一表达式会导致 CPU 突增、GC 压力上升,甚至触发 JIT 线程争用。

典型错误模式是:在循环里或高频请求中对相同结构的 Expression> 反复 Compile(),比如动态构建查询条件时没做缓存。

  • 编译一次平均耗时约 0.1–1ms(取决于表达式复杂度),但并发 100 线程同时编译同一表达式,可能产生上百个等效但互不共享的委托实例
  • 生成的委托对象不可回收——它们被 JIT 和运行时内部强引用,长期驻留内存
  • .NET 6+ 对简单表达式有轻微优化(如常量折叠),但不改变编译本质开销

手动缓存 Expression.Compile() 结果的正确姿势

缓存核心是「键唯一性 + 线程安全」。不能只用 Expression.ToString() 当 key——它不稳定(节点顺序、调试信息可能变),也不反映语义等价性。推荐用表达式结构哈希或标准化后比较。

最简可行方案是用 ConcurrentDictionary,key 由表达式类型 + 关键参数组合生成(例如字段名、操作符、字面值):

网奇.NET网络商城系统
网奇.NET网络商城系统

系统优势: 1、 使用全新ASP.Net+c#和三层结构开发. 2、 可生成各类静态页面(html,htm,shtm,shtml和.aspx) 3、 管理后台风格模板自由选择,界面精美 4、 风格模板每月更新多套,还可按需定制 5、 独具的缓存技术加快网页浏览速度 6、 智能销售统计,图表分析 7、 集成国内各大统计系统 8、 多国语言支持,内置简体繁体和英语 9、 UTF-8编码,可使用于全球

下载
private static readonly ConcurrentDictionary> _cache 
    = new();

public static Func GetFilter(string propertyName, object value) { var key = $"Person_{propertyName}Equals{value}"; return cache.GetOrAdd(key, => { var param = Expression.Parameter(typeof(Person)); var body = Expression.Equal( Expression.Property(param, propertyName), Expression.Constant(value) ); return Expression.Lambda>(body, param).Compile(); }); }

  • 避免把整个 Expression 对象当 key(它没重写 GetHashCode,默认是引用哈希)
  • 不要在 lambda 捕获外部变量(如 value 是局部变量),否则闭包会阻止委托被缓存复用
  • 若表达式含 Expression.Constant(new object()),该对象每次新建,导致 key 不一致——应提前提取为静态只读字段

Expression.Compile() 在 ASP.NET Core 中的常见误用

在控制器或中间件里动态构建并编译表达式(如基于查询字符串生成过滤器),极易成为性能瓶颈点。框架本身不帮你缓存,全靠自己设计生命周期。

  • Scoped 服务里缓存需注意:Scoped 实例随请求创建,缓存无法跨请求共享——应提升到 Singleton 服务中
  • 使用 Microsoft.Extensions.Caching.Memory.IMemoryCache 时,key 必须可序列化且稳定;建议用 MemoryCacheEntryOptions.SlidingExpiration 防止无限增长
  • EF Core 的 Where(expression) 内部已缓存编译结果(针对相同表达式树结构),但仅限于 EF 自己解析的子集;手写复杂表达式仍需自行管理

替代方案:Expression.Compile() 的轻量级选项

如果只是需要“类似委托”的调用能力,且表达式结构固定,可考虑绕过编译:

  • Expression.Evaluate()(需引入 System.Linq.Expressions.Extensions 第三方包)——解释执行,无编译开销,适合低频、调试场景
  • 预定义一组常用表达式模板(如 static readonly Expression> EqualTo = ...),运行时替换参数节点再编译,减少重复生成
  • .NET 7+ 支持 Expression.CompileFast()(非官方 API,来自 FastExpressionCompiler 库),比原生快 2–5 倍,且支持更广的表达式语法

真正复杂的动态逻辑(如用户自定义规则引擎),建议直接上 Roslyn 编译 C# 字符串为程序集,虽然启动慢,但执行期零开销,且可卸载。

相关文章

数码产品性能查询
数码产品性能查询

该软件包括了市面上所有手机CPU,手机跑分情况,电脑CPU,电脑产品信息等等,方便需要大家查阅数码产品最新情况,了解产品特性,能够进行对比选择最具性价比的商品。

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
什么是中间件
什么是中间件

中间件是一种软件组件,充当不兼容组件之间的桥梁,提供额外服务,例如集成异构系统、提供常用服务、提高应用程序性能,以及简化应用程序开发。想了解更多中间件的相关内容,可以阅读本专题下面的文章。

178

2024.05.11

Golang 中间件开发与微服务架构
Golang 中间件开发与微服务架构

本专题系统讲解 Golang 在微服务架构中的中间件开发,包括日志处理、限流与熔断、认证与授权、服务监控、API 网关设计等常见中间件功能的实现。通过实战项目,帮助开发者理解如何使用 Go 编写高效、可扩展的中间件组件,并在微服务环境中进行灵活部署与管理。

213

2025.12.18

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

338

2023.08.02

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1489

2023.10.24

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

258

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

212

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1489

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

621

2023.11.24

Golang 性能分析与pprof调优实战
Golang 性能分析与pprof调优实战

本专题系统讲解 Golang 应用的性能分析与调优方法,重点覆盖 pprof 的使用方式,包括 CPU、内存、阻塞与 goroutine 分析,火焰图解读,常见性能瓶颈定位思路,以及在真实项目中进行针对性优化的实践技巧。通过案例讲解,帮助开发者掌握 用数据驱动的方式持续提升 Go 程序性能与稳定性。

1

2026.01.22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 7.3万人学习

ASP教程
ASP教程

共36课时 | 22.6万人学习

李炎恢ASP基础视频教程
李炎恢ASP基础视频教程

共210课时 | 43.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号