关于.net core高性能编程中的Span<T>和Memory<T>网上资料很多,这里就不说了。今天一直在看ReadOnlySequenceSegment<T>SequenceReader<T>,看得脑壳痛,本篇着重说说对ReadOnlySequenceSegment<T>的理解。

如果对Span<T>和Memory<T>不了解,可以暂时理解为byte[],最好先去搜下相关资料。缓冲区相关知识可以参考官方文档:https://docs.microsoft.com/zh-cn/dotnet/standard/io/buffers

内存片段ReadOnlySequenceSegment<T>

假设你已经了解了Memory<T>,它表示一段连续的内存,有时候我们读取一条数据,它可能并不是存在连续的内存中。

这个我理解得不是很准确,但总体来说就是我们一个完整的数据分成了多个内存片段,每个内存片段用Memory<byte>(你也可以暂时理解为byte[])表示,那么可以以链表的形式,从逻辑上来表示这段完整的数据。比如Memory1上有个next属性指向Memory2,同理Memory2上的next属性指向Memory3,这样的链表就能表示这段完整的数据了。

ReadOnlySequenceSegment<T>就是这样一个链表,3个核心属性定义如下:

 public ReadOnlyMemory<T> Memory { get; protected set; }
public ReadOnlySequenceSegment<T>? Next { get; protected set; }
public long RunningIndex { get; protected set; }
  • Memory:表示这个链表节点下的内存数据,也就是上面的Memory1、2、3
  • Next:就是指向的下一个节点
  • RunningIndex:指当前节点之前的节点的数据之和,比如Memory1里有1个字节、Memeory2里有2个字节,那么Memory3对应节点的RunningIndex就是3

这玩意是个抽象类,不过暂时可以不关心,因为我们通常开发时都可以从某个方法的参数获得ReadOnlySequenceSegment<T>(下面马上会说),而它里面就保存着这个链表的收尾两个节点。

这里重点记住:

  • ReadOnlySequenceSegment里面存储的ReadOnlyMemory<T>(理解上约等于byte[])
  • 多个ReadOnlySequenceSegment可以组成一个链表,从逻辑上表示一个完整的数据,ReadOnlySequenceSegment只是其中一个节点

内存片段容器ReadOnlySequence<T>

上面说的这个内存片段链表其实已经可以从逻辑上表示一段完整的数据了,但是ReadOnlySequenceSegment<T>只是这个链表中的一个节点,它能提供的属性、方法等api只能针对自己这个节点,所以需要一个容器来容纳整个链表,以提供对此连续内存片段操作的api

这里说的容器不是很准确,因为ReadOnlySequence只是存储了整个链表的首位节点,但是由于是链表,其实只要知道首节点,就可以通过Next递归获得整个链表的所有节点,因此我这里把它称为容器

下面引用官方文档的一张图

绿色框中有3段蓝色块,我们可以理解为是链表中的一个节点(ReadOnlySequenceSegment),由于这个节点内部重要的就是保存着具体的数据Memory<T>,所以我们可以简单的看成是3个Memory<T>,这里便于理解,也可以看成是3个byte[]。
根据绿色部分的3个不连续的内存片段,可以生成一个表示逻辑上连续的内存片段集合ReadOnlySequence,这个ReadOnlySequence包含3个Memory<T>,其中首位的片段只取原始片段的一部分。下面我根据理解再来一张图

注:上面简写的16进制,A=0x0A

连续内存片段中的索引SequencePosition

只要知道一个数据在哪个片段中,并且知道它在这个片段中的哪个位置,就能表示一个具体的索引了。

但特别注意这个索引是针对原始链表来说的,也就是上面绿色快的部分,比如图片中的“4”在第1段的索引3的位置;“A”,在第2段的索引2处。这种情况没有办法用单个数字来表示索引,因此单独定义了SequencePosition来表示索引。

ReadOnlySequence的api

  • 构造函数ReadOnlySequence(ReadOnlySequenceSegment<T> startSegment, int startIndex, ReadOnlySequenceSegment<T> endSegment, int endIndex)

    • startSegment:链表的首个节点
    • startIndex:首个节点不一定完全加入到ReadOnlySequence,此参数表示从第几个值开始
    • endSegment:链表的尾节点
    • endIndex:尾节点也不一定完全加入ReadOnlySequence,此参数表示要加入的索引+1
    • 按上图所示,代码应该这样:new  ReadOnlySequence(片段1,3,片段3,1); 注意最后一个参数是1,可以简单理解为在尾节点取前几个值加入到ReadOnlySequence
  • End:就是最后一个片段的最后一个数据的索引对象,就是图片中的片段3索引1
  • Start:第一个片段的索引,片段1,索引2
  • Length:ReadOnlySequence包含的值的长度,按图中就是4 5 6 ....D F 2  长度为10
  • GetPosition(int index):获取第几个值的索引对象,比如GetPosition(0),那就是黄色块的0为4,它所处于绿色块的索引为:片段1,索引2;GetPosition(4),那就是黄色块的2,所处绿色快的片段2,索引1
  • PositionOf(T value):查早某个值在这个序列中所处的索引,比如PositionOf(4),那就是在黄色块的片段1的索引0处,最终结果就是绿色块片段1的索引3处
  • Slice():从这个连续内存片段集合中指定索引处开始,取一段数据,返回的是一个新的ReadOnlySequence。有几个重载,比较容易猜到它的意义
  • bool TryGet(ref SequencePosition position, out ReadOnlyMemory<T> memory, bool advance = true)

    尝试从指定索引处开始读取,所指定的索引处所在片段还有剩余数据,则本次读取这些剩余数据,否则读取下一个片段的数据。最终若读取成功,则返回true,且将读取到的数据赋值给memory参数。advance为true时,position将被直接赋值为下一个片段的索引0处。理解这个再看官方文档那个循环就容易了。

主要api就这几个。

后续

即使自己造轮子时不在乎性能,在使用一些第三方库时也可能会遇到此对象,对它有些了解的话不至于太迷茫。.net core中提供了System.Buffers命名空间,里面包含好几个跟字节数组处理相关的类,后面学到哪里就纪录到哪里。它是System.IO.Pipelines的基础。而System.IO.Pipelines又是编写高性能程序必不可少的玩意。

下一篇学完SequenceReader<T>再写...它帮助我们更简单的读取ReadOnlySequence

c#中的ReadOnlySequenceSegment<T>和ReadOnlySequenceSegment<T>的更多相关文章

  1. Python开源框架

    info:更多Django信息url:https://www.oschina.net/p/djangodetail: Django 是 Python 编程语言驱动的一个开源模型-视图-控制器(MVC) ...

  2. .net core中的高效动态内存管理方案

    .net core在新增的System.Buffers中引入了一大堆高效内存管理的类,如span和memory.内存池.本文今天这里介绍一个高效动态内存访问方案. ReadOnlySequenceSe ...

  3. mapreduce中一个map多个输入路径

    package duogemap; import java.io.IOException; import java.util.ArrayList; import java.util.List; imp ...

  4. Hadoop 中利用 mapreduce 读写 mysql 数据

    Hadoop 中利用 mapreduce 读写 mysql 数据   有时候我们在项目中会遇到输入结果集很大,但是输出结果很小,比如一些 pv.uv 数据,然后为了实时查询的需求,或者一些 OLAP ...

  5. Python中的多进程与多线程(一)

    一.背景 最近在Azkaban的测试工作中,需要在测试环境下模拟线上的调度场景进行稳定性测试.故而重操python旧业,通过python编写脚本来构造类似线上的调度场景.在脚本编写过程中,碰到这样一个 ...

  6. .NET Core中的认证管理解析

    .NET Core中的认证管理解析 0x00 问题来源 在新建.NET Core的Web项目时选择“使用个人用户账户”就可以创建一个带有用户和权限管理的项目,已经准备好了用户注册.登录等很多页面,也可 ...

  7. Angular杂谈系列1-如何在Angular2中使用jQuery及其插件

    jQuery,让我们对dom的操作更加便捷.由于其易用性和可扩展性,jQuer也迅速风靡全球,各种插件也是目不暇接. 我相信很多人并不能直接远离jQuery去做前端,因为它太好用了,我们以前做的东西大 ...

  8. 关于CryptoJS中md5加密以及aes加密的随笔

    最近项目中用到了各种加密,其中就包括从没有接触过得aes加密,因此从网上各种查,官方的一种说法: 高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学 ...

  9. In-Memory:在内存中创建临时表和表变量

    在Disk-Base数据库中,由于临时表和表变量的数据存储在tempdb中,如果系统频繁地创建和更新临时表和表变量,大量的IO操作集中在tempdb中,tempdb很可能成为系统性能的瓶颈.在SQL ...

随机推荐

  1. 解决 Could not resolve type alias 'com.deppon.gis.module.job.server.util.SdoGeometryTypeHandler'. 的办法

    单元测试提示下面错误: 核心错误: Failed to parse mapping resource: 'file [D:\490993\安装程序\DPAP2.1\dpap_v2.0.1\dpap_v ...

  2. VUE 中引入百度地图(vue-Baidu-Map)

    1.安装 $ npm install vue-baidu-map --save 2.全局注册,在main.js中引入以下代码 import BaiduMap from 'vue-baidu-map' ...

  3. J20航模遥控器开源项目系列教程(一)制作教程 | 基础版V1.0发布,从0到1

    我们的开源宗旨:自由 协调 开放 合作 共享 拥抱开源,丰富国内开源生态,开展多人运动,欢迎加入我们哈~ 和一群志同道合的人,做自己所热爱的事! 项目开源地址:https://github.com/C ...

  4. lammps_data文件

    一.notes: 1.不在data文件里写“#”(注释),否则,容易出错: 2.前两行不用写东西(建议): 3.相互作用系数可以不用写在data里边(如pair_coeff等),可有可无,but fo ...

  5. muduo源码解析10-logstream类

    FixedBuffer和logstream class FixedBuffer:noncopyable { }: class logstream:noncopyable { }: 先说一下包含的头文件 ...

  6. ASP.NET Core3.1使用IdentityServer4中间件系列随笔(三):创建使用[ClientCredentials客户端凭证]授权模式的客户端

    配套源码:https://gitee.com/jardeng/IdentitySolution 上一篇<ASP.NET Core3.1使用IdentityServer4中间件系列随笔(二):创建 ...

  7. 使用手机安装Windows系统------DriveDroid

    今天给大家推荐的软件是: DriveDroid 1.说来都是无奈,前一段时间,重装系统结果按完之后进不去系统,然后手贱又把U启动盘给弄坏了 2.本来想这下需要去找同学借个电脑了,然后就想手机可不可以啊 ...

  8. mysql建数据库的字符集与排序规则说明

    本文转自https://blog.csdn.net/qq_38224812/article/details/80745868,感谢作者,自己留存已备他日使用 1.字符集说明: 一般选择utf8.下面介 ...

  9. Python 逆向抓取 APP 数据

    今天继续给大伙分享一下 Python 爬虫的教程,这次主要涉及到的是关于某 APP 的逆向分析并抓取数据,关于 APP 的反爬会麻烦一些,比如 Android 端的代码写完一般会进行打包并混淆加密加固 ...

  10. or2?Scum!(周期性求解)

    链接:https://ac.nowcoder.com/acm/contest/316/E 来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 131072K,其他语言2621 ...