c# 高并发下的结构体struct和类class的性能差异

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

struct 在高并发下为什么比 class 更快

因为

struct
是值类型,分配在栈上(或内联在容器中),不经过 GC;而
class
是引用类型,每次
new
都触发堆分配,高并发时会快速产生大量短生命周期对象,加剧 GC 压力——尤其是 Gen0 频繁回收,直接拖慢吞吐量。

多个线程同时
new MyClass()
→ 多个堆内存请求 → 竞争 GC heap lock(.NET 6+ 改进但仍有开销)
同一线程内循环创建
MyStruct
→ 栈指针偏移即可,无同步、无跟踪、无 finalizer 开销
结构体被用作字典键、队列元素、Span 内容时,避免装箱和指针间接访问

什么时候 struct 反而更慢

当结构体过大(通常 >16 字节)或频繁按值传递时,复制成本会反超引用传递。高并发场景下尤其明显:比如一个 64 字节的

struct
被当作方法参数传入 10 万次/秒,CPU 缓存带宽和寄存器压力会显著上升。

方法签名含
MyLargeStruct s
(而非
ref MyLargeStruct s
)→ 每次调用复制全部字段
放进
List<mylargestruct></mylargestruct>
→ 扩容时整块内存 memcpy,比
List<myclass></myclass>
的指针数组复制重得多
被闭包捕获或用在 async 方法中 → 可能被提升为堆分配(.NET 5+ 对 ref struct 有严格限制,普通 struct 也可能逃逸)

高并发典型场景下的实测建议

以高频消息处理(如 WebSocket 心跳包解析、订单快照生成)为例,优先用

struct
,但必须满足「小、不可变、无引用字段」三原则:

public readonly struct OrderSnapshot
{
    public readonly long OrderId;
    public readonly decimal Price;
    public readonly int Status;
    public readonly DateTime Timestamp;
    public OrderSnapshot(long id, decimal price, int status, DateTime ts)
    {
        OrderId = id;
        Price = price;
        Status = status;
        Timestamp = ts;
    }
}
字段全用
readonly
,避免意外修改引发线程安全问题
不含
string
List<t></t>
object
等引用类型字段(否则仍需 GC 管理)
构造函数不调用虚方法、不触发静态构造器或复杂初始化逻辑 若需序列化,用
Span<byte></byte>
+
BinaryPrimitives
直接写入,避开
JsonSerializer.Serialize<class></class>
的反射开销

容易被忽略的陷阱:struct 的线程局部性假象

很多人以为

struct
天然线程安全,其实不然。多个线程操作同一个可变
struct
实例(比如共享在 static 字段或 ConcurrentQueue 中)会导致读写撕裂——因为 struct 复制是逐字段进行的,非原子。

public static MyMutableStruct SharedData;
→ 线程 A 写
SharedData.X
,线程 B 同时读整个
SharedData
,可能拿到 X 新值 + Y 旧值
即使加了
lock
,若锁粒度覆盖不到所有字段访问路径,仍可能出错
正确做法:要么彻底不可变(
readonly struct
),要么改用
class
+ 显式同步,或者用
Interlocked
操作单个字段
高并发下 struct 和 class 的性能边界不在“定义”,而在“怎么用”——字段大小、生命周期、是否逃逸、是否共享,每一步都可能让预期优势反转。

相关推荐