如何高效地使用数组
- 使用
Span<T> - 使用
ArrayPool
Span
- 快速访问连续内存
- 包括托管内存和非托管内存
- 数组和长字符串,常常会用
Span<T>
Span与数组 - 创建Span和修改元素内容
new Span<数组元素类型>(数组)创建Span实例的时候,不复制数组元素Span有索引器[],访问Span的元素- 由于不复制数组元素,因此修改Span的元素,也相当于直接修改了数组元素
private static Span<int> IntroSpans()
{
int[] arr1 = { 2, 4, 6, 8, 10, 12 };
var span1 = new Span<int>(arr1);
span1[1] = 11;
Console.WriteLine($"arr1[1] is changed via span1[1]: {arr1[1]}");
Console.WriteLine();
return span1;
}
Span与数组 - 切片
- 切片,就是指,访问数组的一部分
- 用
Span做数组切片时,不复制数组元素 - 两个时机,可以做数组切片
- 创建
Span的时候,new Span<T>(数组, 数组起始index, 切片长度) - 调用
Span的方法Slice(数组起始index, 切片长度)
- 创建
private static Span<int> CreateSlices(Span<int> span1)
{
Console.WriteLine(nameof(CreateSlices));
int[] arr2 = { 3, 5, 7, 9, 11, 13, 15 };
var span2 = new Span<int>(arr2);
var span3 = new Span<int>(arr2, start: 3, length: 3);
var span4 = span1.Slice(start: 2, length: 4);
DisplaySpan("content of span3", span3);
DisplaySpan("content of span4", span4);
Console.WriteLine();
return span2;
}
private static void DisplaySpan(string title, ReadOnlySpan<int> span)
{
Console.WriteLine(title);
for (int i = 0; i < span.Length; i++)
{
Console.Write($"{span[i]}.");
}
Console.WriteLine();
}
输出:
CreateSlices
content of span3
9.11.13.
content of span4
6.8.10.12.
Span与数组 - 改变值
Clear(), 如果元素类型为int, 则用0来填充Fill(), 用给定值来填充CopyTo(), 从头上的位置开始粘贴填充,如果目标Span不够大,会报出ArgumentExceptionTryCopyTo(), 如果目标Span不够大,不会报出异常,而是返回false
private static void ChangeValues(Span<int> span1, Span<int> span2)
{
//Clear()
Console.WriteLine(nameof(ChangeValues));
Span<int> span4 = span1.Slice(start: 4);
span4.Clear();
DisplaySpan("content of span1", span1);
//Fill()
Span<int> span5 = span2.Slice(start: 3, length: 3);
span5.Fill(42);
DisplaySpan("content of span2", span2);
//CopyTo()
span5.CopyTo(span1);
DisplaySpan("content of span1", span1);
//TryCopyTo()
if (!span1.TryCopyTo(span4))
{
Console.WriteLine("Couldn't copy span1 to span4 because span4 is too small");
Console.WriteLine($"length of span4: {span4.Length}, length of span1: {span1.Length}");
}
Console.WriteLine();
}
输出:
ChangeValues
content of span1
2.11.6.8.0.0.
content of span2
3.5.7.42.42.42.15.
content of span1
42.42.42.8.0.0.
Couldn't copy span1 to span4 because span4 is too small
length of span4: 2, length of span1: 6
Span与数组 - 只读Span
三种创建只读Span的方式:
- 直接new一个ReadOnlySpan
- 直接将Span赋给ReadOnlySpan
- 直接将数组赋给ReadOnlySpan
private static void ReadonlySpan(Span<int> span1)
{
Console.WriteLine(nameof(ReadonlySpan));
int[] arr = span1.ToArray();
//直接new一个ReadOnlySpan
ReadOnlySpan<int> readOnlySpan1 = new ReadOnlySpan<int>(arr);
DisplaySpan("readOnlySpan1", readOnlySpan1);
//直接将Span赋给ReadOnlySpan
ReadOnlySpan<int> readOnlySpan2 = span1;
DisplaySpan("readOnlySpan2", readOnlySpan2);
//直接将数组赋给ReadOnlySpan
ReadOnlySpan<int> readOnlySpan3 = arr;
DisplaySpan("readOnlySpan3", readOnlySpan3);
Console.WriteLine();
}
输出:
ReadonlySpan
readOnlySpan1
42.42.42.8.0.0.
readOnlySpan2
42.42.42.8.0.0.
readOnlySpan3
42.42.42.8.0.0.