C# Span<T> 高效内存操作
学习使用 Span<T> 进行无分配的内存切片操作,提升性能。 · 难度:入门 · +15XP
Span 是什么?
Span<T> 是 C# 7.2 引入的一个值类型,用于表示连续内存区域的切片。它不分配堆内存,支持数组、字符串、栈内存等多种底层存储,是高性能编程的重要工具。
创建 Span
可以从数组、字符串或栈内存创建:
// 从数组创建
int[] arr = { 1, 2, 3, 4, 5 };
Span<int> span1 = arr.AsSpan();
// 从数组切片
Span<int> slice = arr.AsSpan(1, 3); // {2, 3, 4}
// 从字符串
string text = "Hello";
ReadOnlySpan<char> chars = text.AsSpan();
// 栈内存
Span<byte> stackSpan = stackalloc byte[100];
常用操作
Span 支持索引、切片、修改等操作:
Span<int> numbers = new int[] { 10, 20, 30, 40, 50 };
numbers[2] = 35; // 修改元素
var sub = numbers.Slice(0, 3); // {10, 20, 35}
sub.Fill(0); // 全部填充为0
Console.WriteLine(numbers[0]); // 0Span 与数组对比
| 特性 | Span<T> | 数组 |
|---|---|---|
| 内存分配 | 无(引用现有内存) | 堆分配 |
| 切片性能 | O(1),无复制 | O(n),需复制 |
| 堆限制 | 只能存在于栈上 | 可存在于堆上 |
| 修改能力 | 可读写(ReadOnlySpan 只读) | 可读写 |
性能示例
处理大型数组时,Span 避免了子数组的分配:
void ProcessData(Span<int> data)
{
for (int i = 0; i < data.Length; i++)
data[i] *= 2;
}
int[] bigArray = Enumerable.Range(1, 1000000).ToArray();
ProcessData(bigArray.AsSpan(100, 500)); // 仅处理部分,无分配
练习提示
编写一个方法,使用 Span<int> 计算数组切片中所有偶数的和。尝试分别使用 Span 和 LINQ 实现,比较代码简洁性和性能。