1. Span<T>的特性
- system.span<T>在.net core 2.0版本引入
- 它適用于對連續內存的操作,而不產生新的內存分配,比如數組、字符串、堆外內存
- 類型為ref struct,不能作為參數傳遞,不能被裝箱(不能作為類的字段),不能作為async的返回值,只能是現用現聲明,用來對原始數組操作
- 可以通過stackalloc在棧上分配內存,不涉及堆分配和垃圾回收
- 因為不涉及堆內存分配,所以性能比較高
1.1 Span<T>?的一些典型用法示例:
- 對已有的數組進行切片操作,無需創建新數組:
int[] numbers = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };// 獲取一個數組切片slice,現在指向 numbers 的子區域,包含元素 2, 3, 4, 5, 6
Span<int> slice = numbers.AsSpan().Slice(start: 2, length: 5);
- 在不需要副本的情況下操作字符串:
string str = "Hello, World!";
//獲取字符串的一個切片,span 現在指向字符串 "World"
//注意:這里使用 ReadOnlySpan<char> 因為字符串是不可變的
ReadOnlySpan<char> span = str.AsSpan().Slice(start: 7, length: 5);
- 處理從文件或網絡讀取的數據緩沖區:
-
//假設這是從文件或網絡讀取的數據 byte[] buffer = new byte[1024];//現在可以使用 bufferSpan 進行讀取和寫入操作,而不需要復制數據 Span<byte> bufferSpan = buffer.AsSpan();
- 棧分配數組(通過 stackalloc)
//在棧上分配內存,不涉及堆分配或垃圾回收
Span<int> stackAllocatedArray = stackalloc int[10];
for (int i = 0; i < stackAllocatedArray.Length; i++)
{ stackAllocatedArray[i] = I;
}
- 圖像處理和音頻緩沖操作等領域,需要高性能內存操作:
-
//假設有一個表示圖像像素的 byte 數組 byte[] imagePixels = new byte[width * height * bytesPerPixel]; Span<byte> imageSpan = imagePixels.AsSpan(); // 對圖像進行處理,例如反轉顏色 for (int i = 0; i < imageSpan.Length; i += bytesPerPixel) { imageSpan[i] = (byte)(255 - imageSpan[i]); // R imageSpan[i + 1] = (byte)(255 - imageSpan[i + 1]); // G imageSpan[i + 2] = (byte)(255 - imageSpan[i + 2]); // B // 如果是 RGBA 格式,還需要處理 Alpha 通道 }
Span<T>的這些用法展示了它如何提供對內存的高效訪問,同時保持類型安全。由于 Span<T>是 `ref struct`,它具有一些限制,例如不能被裝箱、不能作為異步方法的返回值,也不能存儲在堆上,這些限制有助于保持其性能優勢。
2. ref struct的特性
- 特殊的值類型
- 不能被裝箱,不能作為類的字段,不能作為異步方法的返回值
- 不涉及堆內存分配,性能比較高
2.1 ref struct 與 值類型的區別
- 值類型可以被裝箱,可以作為類的字段
- ref struct 不能被裝箱,不可以作為類的字段