Pipelines

Pipelines

我们从stream流说起,tream的API 相对来说,大家都很熟悉。

流有些什么问题呢?模糊:在不同场景里使用不同的工作模式:

  • 有时时只读,有时只写,有时又是读写同时。

  • 即使同一个情况下,都有可能一会只读,一会儿只写(比如:DeflateStream)

  • 在一些双重流(NetworkStream,SslStream)情况下,几乎不可能知道数据何时终止传输了,只能不断的使用循环处理。

  • 流提供的定位操作也不同,有的是length,有的是Position

  • 大量的数据拷贝,内存分配。 有鉴如此,pipelines 在.NET Core 2.1 加入。

pipelines是什么 pipelines可以理解为提供了一组二进制流访问的API,包含内存管理(内存的合并、回收),流控(积压与防溢出),多线程管理。

先看列子

  • Stream
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    using (MemoryStream ms = new MemoryStream())
    {
        WriteSomeData(ms);
        ms.Position = 0;
        ReadSomeData(ms);
    }
    void WriteSomeData(Stream stream)
    {
        byte[] bytes = Encoding.ASCII.GetBytes("hello, world!");
        stream.Write(bytes, 0, bytes.Length);
        stream.Flush();
    }
    void ReadSomeData(Stream stream)
    {
        int bytesRead;
        byte[] buffer = new byte[256];
        do
        {
            bytesRead = stream.Read(buffer, 0, buffer.Length);
            if (bytesRead > 0)
            {  
                string s = Encoding.ASCII.GetString(buffer, 0, bytesRead);
                Console.Write(s);
            }
        } while (bytesRead > 0);
    }

      

  • Pipelines
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    async Task ProcessPipe()
    {
      Pipe pipe = new Pipe();
      await WriteSomeDataAsync(pipe.Writer);
      pipe.Writer.Complete();
      await ReadSomeDataAsync(pipe.Reader);
    }
    async ValueTask WriteSomeDataAsync(PipeWriter writer)
    {
        Memory<byte> workspace = writer.GetMemory(512);
        int bytes = Encoding.ASCII.GetBytes(
            "hello, world!", workspace.Span);
        writer.Advance(bytes);
        await writer.FlushAsync();
    }
    async ValueTask ReadSomeDataAsync(PipeReader reader)
    {
        while (true)
        {
            ReadResult read = await reader.ReadAsync();
            ReadOnlySequence<byte> buffer = read.Buffer;
            if (buffer.IsEmpty && read.IsCompleted)
                break;
            if(buffer.IsSingleSegment)
            {
                 Encoding.ASCII.GetString(buffer.First);
            }else
            {
                foreach (Memory<byte> segment in buffer)
                {
                string s = Encoding.ASCII.GetString(segment.Span);
                Console.Write(s);
                 }
            }
            reader.AdvanceTo(buffer.End);
        }
    } 

pipeline 提供了两个独立的读写API处理读写问题。

pipewriter:

处理写操作,pipeline使用GetMemory获取内存区替代显示分配byte[] 。然后向管道写入数据。这里并不是只能使用512个字节,可以零字节,也可以一万字节,通过Advance(bytes) 完成单次的数据写入,同时告知管道有多少数据可以被reader消费。之后Flush管道。

数据写入完成之后,调用complete方法,通知管道写入操作结束。

pipereader:

read.IsCompleted表示writer是否执行complete。

buffer.IsEmpty告诉我们单前迭代种管道是否已经没有数据。

AdvanceTo告诉管道我们已经消费了多少数据。

另外

上面的列子我们使用AdvanceTo(buffer.End),把一切都消费掉了。更一般的情况可能是自定义的数据的格式或者通过 cr/lf来处理数据隔断等,即可能一次消费的长度是小于521或者大于512字节。 ReadOnlySequence<byte>

  • Slice()方法通过切片可以返回我们真实需要处理的数据。

  • GetPosition()获取相对处理的位置。

  • reader.AdvanceTo(consumedToPosition, buffer.End)告诉管道我们已经消费了多少位置,同时检查了所有数据,对于消费点到结束点数据我们不能处理,我们需要更多的数据来处理。

回过头在看看PipeWriter.FlushAsync()PipeReader.ReadAsync()。他们之间有微妙的平衡。

  1. ReadAsync 表示管道需要数据,会唤醒reader,执行读取循环。

  2. 如果写超过了读,管道里数据已经充满,读取操作没有读数据,则阻塞写操作。如果管道中有更多的空位置的时候,写入数据会重新开始。

作者:RunStone

出处:https://www.cnblogs.com/RunStone/p/11161581.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   奔跑石头  阅读(853)  评论(0编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
more_horiz
keyboard_arrow_up light_mode palette
选择主题
点击右上角即可分享
微信分享提示