c# 在高并发场景下,委托和接口调用的性能对比

来源:这里教程网 时间:2026-02-21 17:36:27 作者:

委托调用比接口调用快,但差距通常在纳秒级

在高并发、低延迟敏感的场景(比如高频交易网关、实时游戏服务器逻辑分发),

delegate
调用确实比
interface
调用略快。根本原因是:委托是直接的函数指针跳转,而接口调用需经过虚方法表(vtable)查找 —— 即使 JIT 已做内联优化,接口调用仍多一次间接寻址。实测在 .NET 6+ Release 模式下,空方法调用的单次开销差异约 1–3 ns,非空逻辑中该差值会被业务代码完全淹没。

接口调用在哪些情况下会明显变慢

以下情况会让接口调用相对更重,放大与委托的差距:

接口方法未被 JIT 内联(如含循环、异常处理、跨程序集调用,或标记了
[MethodImpl(MethodImplOptions.NoInlining)]
实现类是泛型类且未被提前实例化(导致每次调用都触发泛型字典查找) 接口有多个实现,且运行时类型不固定(JIT 难以做单态内联,退化为多态内联或完全不内联)
unsafe
上下文外频繁调用跨堆对象(如 COM 对象或旧版 COM Interop 接口)

委托不是万能加速器:容易踩的坑

盲目用委托替代接口可能引入更严重的问题:

委托实例本身有内存开销:
Action<t></t>
是引用类型,每次
new Action<int>(MyMethod)</int>
都分配对象;而接口变量复用同一实例时无额外分配
闭包捕获导致意外的生命周期延长(例如捕获
this
或局部引用,阻止 GC)
无法享受接口的契约约束和编译期检查,重构时易漏掉委托签名变更 调试困难:栈上显示为
Invoke
DynamicInvoke
,丢失原始方法名(尤其用
Delegate.CreateDelegate
动态构造时)
反射创建委托(如
MethodInfo.CreateDelegate
)比直接 new 委托慢 10–100 倍,且无法被 JIT 内联

实操建议:什么场景该选哪个

不用纠结“绝对快”,要看实际瓶颈点。可参考以下判断链:

if (调用频率 > 100K/s && 方法体极轻(纯计算/无 IO/无锁) && 类型确定且稳定) {
    // 可考虑预创建静态委托,如:private static readonly Func<int, int> s_calc = x => x * 2;
} else if (需要解耦、测试替換、DI 容器注入、或实现类动态加载) {
    // 必须用接口 —— 性能损失几乎不可测,且维护性远胜过微秒级收益
} else if (已确认热点在虚调用本身(通过 dotTrace / PerfView 抓到 vcall 占比高)) {
    // 再考虑用委托 + 缓存(如 ConcurrentDictionary<Type, Delegate>),而非全局替换
}

真正卡住高并发服务的,99% 不是接口 vs 委托,而是锁竞争、GC 压力、内存带宽或网络序列化。先抓火焰图,别过早优化调用方式。

相关推荐

热文推荐