杂谈.netcore的Buffer相关新类型
2021-03-18 04:25
标签:为什么 spl tsp private 静态 html dispose 好友 asc
本文将.netcore新出现的与Buffer操作相关的类型进行简单分析与讲解,由于资料有限,一些见解为个人见解,可能不是很准确。这些新类型将包括BinaryPrimitives、Span,Memory,ArrayPool,Memorypool 在网络传输中,最小单位是byte,很多场景,我们需要将int long short等类型与byte[]相互转换。比如,将int转换为BigEndian的4个字节,在过去,我们很容易就想到BitConverter,但BitConverter设计得不够好友,BitConverter.GetBytes(int value)得到的byte[]的字节顺序永远与主机的字节顺序一样,我们不得不再根据BitConverter的IsLittleEndian属性判断是否需要对得到byte[]进行转换字节顺序,而BinaryPrimitives的Api设计为严格区分Endian,每个Api都指定了目标Endian。 BitConverter BinaryPrimitives Span 读写代码1 文章范围
2 BinaryPrimitives
var intValue = 1;
var bytes = BitConverter.GetBytes(intValue);
if (BitConverter.IsLittleEndian == true)
{
Array.Reverse(bytes);
}
var intValue = 1;
var bytes = new byte[sizeof(int)];
BinaryPrimitives.WriteInt32BigEndian(bytes, intValue);
3 Span
]
public void ByteSpan()
{
var span = array.AsSpan();
for (var i = 0; i Benchmark]
unsafe public void BytePointer()
{
fixed (byte* pointer = &array[0])
{
for (var i = 0; i
public class DemoContext
{
private byte[] array = new byte[1024];
[Benchmark]
public void ByteArray()
{
for (var i = 0; i Benchmark
Benchmark报告
| Method | Mean | Error | StdDev |
|------------ |---------:|--------:|--------:|
| ByteArray | 577.4 ns | 9.07 ns | 8.48 ns |
| ByteSpan | 323.8 ns | 0.87 ns | 0.81 ns |
| BytePointer | 499.4 ns | 4.09 ns | 3.82 ns |
Memory
如果尝试将Span作为全局变量,或在异步方法声明为变量,你会得到编译器的错误,原因不在本文讲解范围内,而Memory类型可以满足这些需求,Memory提供了用于数据读写的Span属性,这个Span属性是每将获取时都有一些计算,所以我们应该尽量避免多次获取它的Span属性。
合理的获取Span
var span = memory.Span;
for (var i = 0; i
不合理的获取Span
for (var i = 0; i
Benchmark报告
| Method | Mean | Error | StdDev |
|------------ |-----------:|---------:|---------:|
| ByteMemory1 | 325.8 ns | 1.03 ns | 0.97 ns |
| ByteMemory2 | 3,344.9 ns | 11.91 ns | 11.14 ns |
ArrayPool
ArrayPool用于解决频繁申请内存和释放内存导致GC压力过大的场景,比如System.Text.Json在序列对象时为utf8的byte[]时,事先是无法计算最终byte[]的长度的,过程中可能要不断申请和调整缓冲区的大小。在没有ArrayPool加持的情况下,高频次的序列化,则会生产高频创建byte[]的过程,随之GC压力也会增大。ArrayPool的设计逻辑是,从pool申请一个指定最小长度的缓冲区,缓冲区在不需要的时候,将其返回到pool里,待以重复利用。
var pool = ArrayPoolbyte>.Shared;
var buffer = pool.Rent(1024);
// 开始利用buffer
// ...
// 使用结束
pool.Return(buffer);
Rent用于申请,实际上是租赁,Return是归还,返回到池中。我们可以使用IDisposable接口来包装Return功能,使用上更方便一些:
///
/// 定义数组持有者的接口
///
///
public interface IArrayOwner : IDisposable
{
///
/// 获取持有的数组
///
T[] Array { get; }
///
/// 获取数组的有效长度
///
int Count { get; }
}
///
/// 表示共享的数组池
///
public static class ArrayPool
{
///
/// 租赁数组
///
/// 元素类型
/// 最小长度
///
public static IArrayOwner Rent(int minLength)
{
return new ArrayOwner(minLength);
}
///
/// 表示数组持有者
///
///
[DebuggerDisplay("Count = {Count}")]
[DebuggerTypeProxy(typeof(ArrayOwnerDebugView))]
private class ArrayOwner : IDisposable, IArrayOwner
{
///
/// 获取持有的数组
///
public T[] Array { get; }
///
/// 获取数组的有效长度
///
public int Count { get; }
///
/// 数组持有者
///
///
public ArrayOwner(int minLength)
{
this.Array = ArrayPool.Shared.Rent(minLength);
this.Count = minLength;
}
///
/// 归还数组
///
Public void Dispose()
{
ArrayPool.Shared.Return(this.Array);
}
}
///
/// 调试视图
///
///
private class ArrayOwnerDebugView
{
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public T[] Items { get; }
///
/// 调试视图
///
///
public ArrayOwnerDebugView(IArrayOwner owner)
{
this.Items = owner.Array.AsSpan(0, owner.Count).ToArray();
}
}
}
改造之后的使用
using var buffer = ArrayPool.Rentbyte>(1024);
// 尽情的使用buffer吧,自动回收
Memorypool
Memorypool本质上还是使用了ArrayPool,Memorypool只提供了Rent功能,返回一个IMomoryOwner,对其Dispose等同于Return过程,使用方式和我们上面改造过的ArrayPool静态类的使用方式是一样的。
MemoryMarshal静态类
MemoryMarshal是一个工具类,类似于我们指针操作时常常用到的Marshal类,它操作一些更底层的Span或Memory操作,比如提供将不同基元类型的Span相互转换等。
获取Span的指针
var span = new Spanbyte>(new byte[] { 1, 2, 3, 4 });
ref var p0 = ref MemoryMarshal.GetReference(span);
fixed (byte* pointer = &p0)
{
Debug.Assert(span[0] == *pointer);
}
Span泛型参数类型转换
Spanint> intSpan = new Spanint>(new int[] { 1024 });
Spanbyte> byteSpan = MemoryMarshal.AsBytes(intSpan);
ReadonlyMemory转换为Memory
// 相当于给ReadonlyMemory移除只读功能
MemoryT> MemoryMarshal.AsMemoryT>(ReadonlyMemoryT> readonly)
杂谈.netcore的Buffer相关新类型
标签:为什么 spl tsp private 静态 html dispose 好友 asc
原文地址:https://www.cnblogs.com/lonelyxmas/p/12776272.html