C#中的高效IO库System.IO.Pipelines

 更新时间:2022年07月02日 09:33:03   作者:天方  
这篇文章介绍了C#中的高效IO库System.IO.Pipelines,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

我们在编写网络程序的时候,经常会进行如下操作:

  • 申请一个缓冲区

  • 从数据源中读入数据至缓冲区

  • 解析缓冲区的数据

  • 重复第2步

表面上看来这是一个很常规而简单的操作,但实际使用过程中往往存在如下痛点:

数据读不全:

可能不能在一次read操作中读入所有需要的数据,因此需要在缓冲区中维护一个游标,记录下次读取操作的起始位置,这个游标带了了不小的复杂度:

  • 从缓冲区读数据时,要根据游标计算缓冲区起始写位置,以及剩余空间大小。增加了读数据的复杂度。

  • 解析数据也是复用这个缓冲区的,解析的时候也要判断游标起始位置,剩余空间大小。同时增加了解析数据的复杂度。

  • 解析玩了后还要移动游标,重新标记缓冲区起始位置,再次增加了复杂度。

缓冲区容量有限:

由于缓冲区有限,可能申请的缓冲区不够用,需要引入动态缓冲区。这也大幅加大了代码的复杂度。

  • 如果每次都申请更大的内存,一方面带来的内存申请释放开销,另一方面需要将原来的数据移动,并更新游标,带来更复杂的逻辑。

  • 如果靠多段的内存组成一个逻辑整理,数据的读写方式都比较复杂。

  • 使用完后的内存要释放,如果需要更高的效率还要维持一个内存池。

读和用没有分离

我们的业务本身只关心使用操作,但读和用操作没有分离,复杂的都操作导致用操作也变得复杂,并且严重干扰业务逻辑。

今天介绍微软新推出的一个库:System.IO.Pipelines(需要在Nuget上安装),用于解决这些痛点。它主要包含一个Pipe对象,它有一个Writer属性和Reader属性。

var pipe   = new Pipe();
var writer = pipe.Writer;
var reader = pipe.Reader;

Writer对象

Writer对象用于从数据源读取数据,将数据写入管道中;它对应业务中的"读"操作。

var content = Encoding.Default.GetBytes("hello world");
var data    = new Memory<byte>(content);
var result  = await writer.WriteAsync(data);

另外,它也有一种使用Pipe申请Memory的方式

var buffer = writer.GetMemory(512);
content.CopyTo(buffer);
writer.Advance(content.Length);
var result = await writer.FlushAsync();

Reader对象

Reader对象用于从管道中获取数据源,它对应业务中的"用"操作。

首先获取管道的缓冲区:

var result = await reader.ReadAsync();
var buffer = result.Buffer;

这个Buffer是一个ReadOnlySequence<byte>对象,它是一个相当好的动态内存对象,并且相当高效。它本身由多段Memory<byte>组成,查看Memory段的方法有:

  • IsSingleSegment: 判断是否只有一段Memory<byte>

  • First: 获取第一段Memory<byte>

  • GetEnumerator: 获取分段的Memory<byte>

它从逻辑上也可以看成一段连续的Memory<byte>,也有类似的方法:

  • Length: 整个数据缓冲区长度

  • Slice: 分割缓冲区

  • CopyTo: 将内容复制到Span中

  • ToArray: 将内容复制到byte[]中

另外,它还有一个类似游标的位置对象SequencePosition,可以从其Position相关函数中使用,这里就不多介绍了。

这个缓冲区解决了"数据读不够"的问题,一次读取的不够下次可以接着读,不用缓冲区的动态分配,高效的内存管理方式带来了良好的性能,好用的接口是我们能更关注业务。

获取到缓冲区后,就是使用缓冲区的数据

var data = buffer.ToArray();

使用完后,告诉PIPE当前使用了多少数据,下次接着从结束位置后读起

reader.AdvanceTo(buffer.GetPosition(4));

这是一个相当实用的设计,它解决了"读了就得用"的问题,不仅可以将不用的数据下次再使用,还可以实现Peek的操作,只读但不改变游标。

交互

除了"读"和"用"操作外,它们之间还需要一些交互,例如:

  • 读过程中数据源不可用,需要停止使用

  • 使用过程中业务结束,需要中止数据源。

Reader和Writer都有一个Complete函数,用于通知结束:

reader.Complete();
writer.Complete();

在Writer写入和Reader读取时,会获得一个结果

FlushResult result = await writer.FlushAsync();
ReadResult result = await reader.ReadAsync();

它们都有一个IsComplete属性,可以根据它是否为true判断是否已经结束了读和写的操作。

取消

在写入和读取的时候,也可以传入一个CancellationToken,用于取消相应的操作。

writer.FlushAsync(CancellationToken.None);
reader.ReadAsync(CancellationToken.None);

如果取消成功,对应的Result的IsCanceled则为true(没有验证过)

到此这篇关于C#高效IO库System.IO.Pipelines的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • VS2017使用Git进行源代码管理的实现

    VS2017使用Git进行源代码管理的实现

    这篇文章主要介绍了VS2017使用Git进行源代码管理的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07
  • C#图表算法之最短路径

    C#图表算法之最短路径

    本文详细讲解了C#图表算法之最短路径,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-04-04
  • C# paddlerocrsharp识别身份证号的实现示例

    C# paddlerocrsharp识别身份证号的实现示例

    paddlerocrsharp可以进行图片识别,本文主要介绍了C# paddlerocrsharp识别身份证号的实现示例,具有一定的参考价值,感兴趣的可以了解一下
    2024-02-02
  • 详谈C# 图片与byte[]之间以及byte[]与string之间的转换

    详谈C# 图片与byte[]之间以及byte[]与string之间的转换

    下面小编就为大家带来一篇详谈C# 图片与byte[]之间以及byte[]与string之间的转换。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-02-02
  • Unity实现车型识别的示例代码

    Unity实现车型识别的示例代码

    这篇文章主要介绍了在Unity中接入百度AI,实现检测一张车辆图片的具体车型。即对于输入的一张图片(可正常解码,且长宽比适宜),输出图片的车辆品牌及型号。需要的可以参考一下
    2022-01-01
  • C#获取Description特性的扩展类详解

    C#获取Description特性的扩展类详解

    这篇文章主要和大家详细介绍一下C#获取Description特性的扩展类,文中的示例代码讲解详细,对我们学习有一定的帮助,需要的可以参考一下
    2022-06-06
  • C# 设计模式系列教程-简单工厂模式

    C# 设计模式系列教程-简单工厂模式

    简单工厂模式职责单一,实现简单,且实现了客户端代码与具体实现的解耦。
    2016-06-06
  • c# winform取消右上角关闭按钮的实现方法

    c# winform取消右上角关闭按钮的实现方法

    本文是对c#中winform取消右上角关闭按钮的实现方法进行了详细的介绍,需要的朋友可以过来参考下。希望对大家有所帮助
    2013-10-10
  • C#9新特性之增强的模式匹配

    C#9新特性之增强的模式匹配

    这篇文章主要介绍了C#9新特性之增强的模式匹配,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • Quartz.Net任务和触发器实现方法详解

    Quartz.Net任务和触发器实现方法详解

    这篇文章主要介绍了Quartz.Net任务和触发器实现方法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-12-12

最新评论