前面文章"你所不知道的.NET性能提升特性Span<T>"讲述过Span对性能的提升,但是Span有个问题,不能用在异步方法,如下图,使用会报异常,如果改成非异步方法错误消除,那么有类似Span的属性能在异步方法中运行吗?还真有,这就是Memory<T>。.
我们先来看看官网的解释:类似 Span<T>, Memory<T>
表示内存的连续区域。但是Memory<T>
,与引用结构不同Span<T>。这意味着 Memory<T>
可以放置在托管堆上,而 Span<T> 不能。因此,结构 Memory<T>
没有与 Span<T> 实例相同的限制。它可以用作类中的字段。它可以跨await``yield边界使用。
从中可以得出:
static async Task Main(string[] args)
{
var array = new byte[1000000];
var arrayMemory = new Memory<byte>(array);//装载到span
byte data = 0;
for (int i = 0; i < arrayMemory.Length; i++)
{
arrayMemory.Span[i] = data++;
}
int arraySum = 0;
for (int i= 0; i < arrayMemory.Length; i++)
{
arraySum += arrayMemory.Span[i];//这里必须转为Span
}
Console.WriteLine("Memory结果是: {0}", arraySum);
//Memory结果是: 127493856
var strs = new string[] { "java", "c++", "c#", "go", "python" };
var slice = new Memory<string>(strs, 2, 2);
await RunMemory(slice,strs);
}
private static async Task RunMemory(Memory<string> memory, string[] strs)
{
for (int ctr = 0; ctr < memory.Length; ctr++)
memory.Span[ctr] += "牛";
foreach (var value in strs)
Console.Write($"{value} ");
// 结果 java c++ c#牛 go牛 python
}
在异步方法中可以使用,注意赋值或者读取需要转换Span类型才行,另外Memory不支持遍历(具体大家可以查一下资料),上面例子用了for循环。
这里列举了Memory<T>在异步方法的应用和元素切片的使用,还有作为字段和接口等大家可以自己试一试,和Span<T>一样,通常Memory<T>都是包裹数组、字符串,用法也基本相同,只是应用场景不一样而已。参数,异步方法应该使用Memory,同步方法用Span;同一Memory<T>实例不能同时被多个消费者使用等。