Reading Stream中byte[]、Span<Byte>、Memory<Byte>的区别及如何选型?
三种Stream读取实现的核心差异
排除给定的两个已知前提后,三者的核心差异集中在运行时行为、适用场景、性能开销三个维度:
- 基于
byte[]的重载:是.NET最早提供的经典同步API,全版本兼容,不需要额外的类型包装,但内存切片需要手动计算偏移量,容易出现边界溢出类错误,无特殊优化时和后两种写法性能接近。 - 基于
Span<byte>的重载:同样是同步API,Span<byte>是栈分配的ref struct类型,完全没有GC堆分配开销,Runtime自动做内存边界校验,切片操作比手动算偏移更安全高效,但无法跨异步await边界使用,也不能作为类字段长期存储。 - 基于
Memory<byte>的ReadAsync重载:是异步IO专用API,Memory<byte>是普通值类型,支持跨异步上下文传递,同样内置边界校验和便捷的切片能力,适合异步IO场景。额外提一句,示例里直接调用.Result是不良实践,高并发场景下极易触发线程池死锁,建议替换为await调用。
选型判断标准
实际开发中可以按以下优先级判断:
- 优先选
byte[]的场景:- 需要兼容.NET Framework 或低于.NET Core 2.1的老版本 runtime
- 逻辑非常简单,不需要做内存切片操作,也不需要跨上下文传递buffer
- 依赖的第三方库只接受
byte[]类型的参数
- 优先选
Span<byte>的场景:- 纯同步处理逻辑,没有异步await操作
- 追求极致性能,要完全避免额外的GC开销
- 需要频繁做内存切片操作,或者要包装
stackalloc分配的栈内存、非托管内存块
- 优先选
Memory<byte>的场景:- 异步IO处理场景,需要跨await边界传递buffer
- 需要把buffer作为类字段长期存储,跨方法、跨上下文调用
- 同时需要切片的便利性和异步操作支持
内容的提问来源于stack exchange,提问作者cogumel0
相关产品推荐
相关产品推荐

