c# System.IO.Pipelines 和 NetworkStream 的性能对比

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

System.IO.Pipelines 为什么比 NetworkStream 快

根本原因不在“管道”本身,而在内存管理和同步模型。NetworkStream 默认走

Stream.ReadAsync
/
WriteAsync
,每次调用都触发一次
Memory<byte></byte>
ArraySegment<byte></byte>
→ 内部缓冲区拷贝,还常伴随
Task
分配和状态机开销。Pipelines 的
PipeReader
直接暴露
ReadOnlySequence<byte></byte>
,数据零拷贝进入用户逻辑;
PipeWriter
Advance
也只移动指针,不搬运字节。

典型场景下(如 HTTP 解析、Protobuf 反序列化),Pipelines 能减少 30%~60% 的 GC 压力和 20%~40% 的 CPU 时间 —— 尤其在小包高频通信时更明显。

NetworkStream 什么时候反而更简单可靠

不是所有场景都值得为性能上 Pipelines。如果你只是做一次性 TCP 连接、协议简单(比如发个 JSON 请求拿个响应)、吞吐量低于 1K QPS,NetworkStream 的代码量和调试成本显著更低。

NetworkStream
天然支持
Timeout
属性(
ReadTimeout
/
WriteTimeout
),而 Pipelines 需手动结合
CancellationToken
+
ValueTask
状态判断
异常堆栈更直白:
IOException: Unable to read data from the transport connection
比 Pipelines 中
InvalidOperationException: Cannot await a completed result
更容易定位网络中断
HttpClient
TcpClient.GetStream()
无缝衔接,无额外适配层

真实压测中 Pipelines 的关键配置陷阱

没调好

PipeOptions
,Pipelines 可能比 NetworkStream 还慢。常见误配:

默认
PipeOptions.PoolSize = 4096
,但高并发下小 buffer 频繁分配会触发 GC —— 建议设为
8192
或更高(需权衡内存占用)
MinimumSegmentSize
设太小(如 512)会导致大量小段内存碎片;设太大(如 1MB)又浪费;推荐 4KB~16KB 区间,匹配多数网卡 MTU
漏掉
UseSynchronizationContext = false
,在 ASP.NET Core 默认同步上下文里会引发线程争用

正确初始化示例:

var options = new PipeOptions(
    pool: ArrayPool<byte>.Create(8192, 1024),
    minimumSegmentSize: 4096,
    useSynchronizationContext: false);
var pipe = new Pipe(options);

从 NetworkStream 迁移到 Pipelines 的最小改动路径

不要重写整个通信层。优先替换接收侧,保留 NetworkStream 发送逻辑过渡:

TcpClient.GetStream()
获取
NetworkStream
后,立即包装成
StreamPipeReader
new StreamPipeReader(stream, options)
发送仍用
stream.WriteAsync(...)
,等读侧稳定后再把写逻辑迁到
PipeWriter
注意:Pipelines 不自动处理粘包/半包,必须自己实现
SequenceReader
边界判断 —— 别直接用
reader.TryRead(out var result)
就解析,要循环直到满足协议长度

粘包处理示意:

while (true)
{
    var result = await reader.ReadAsync(ct);
    var buffer = result.Buffer;
    if (!buffer.IsEmpty)
    {
        var reader = new SequenceReader<byte>(buffer);
        while (reader.TryReadLittleEndian(out int len) && reader.Remaining >= len)
        {
            // 解析 len 字节的有效载荷
            reader.Advance(len);
        }
        reader.AdvanceTo(buffer.Start, buffer.End);
    }
    if (result.IsCompleted) break;
}

Pipelines 的性能优势只有在协议解析逻辑足够轻、且连接复用率高时才真正释放。单次短连接 + 复杂 JSON 序列化,NetworkStream 可能更省心。

相关推荐