如何表示 Span<T> 列表/数组
Posted
技术标签:
【中文标题】如何表示 Span<T> 列表/数组【英文标题】:How to represent Span<T> list/array 【发布时间】:2019-01-20 13:47:53 【问题描述】:我想交错几个内存/跨度缓冲区。是否可以在不重复访问内部循环中的 Span 属性的情况下做到这一点?
public static void Interleave(StreamWriter s, ReadOnlyMemory<float>[] data)
for (int i = 0; i < data.First().Length; i++)
for (int j = 0; j < data.Length; j++)
s.Write(data[j].Span[i]);
【问题讨论】:
不完全确定您要实现的目标,但访问Span
属性是使用 ReadOnlyMemory 缓冲区的方法(它的存在是因为它的对应物 ReadOnlySpan 只能存在于堆栈上,@ 987654321@)
【参考方案1】:
我没有找到表示Span<int>[]
或Span<Span<int>>
的方法,但我使用递归不安全函数通过int**
指针实现了类似的结果。不幸的是,它不能很好地概括。
| Method | Mean | Error | StdDev |
|----------------------- |---------:|----------:|----------:|
| InterleaveArray | 1.405 ms | 0.0125 ms | 0.0111 ms |
| InterleaveMemorySpan | 4.232 ms | 0.0659 ms | 0.0616 ms |
| UnsafeInterleaveMemory | 1.374 ms | 0.0143 ms | 0.0134 ms |
请注意,重复访问 Memory 上的 Span 属性比其他两个实现慢 3 倍。这是我使用的代码:
public class InterleaveTests
private Action<int> act = x => ;
public static int[][] CreateBuffers(int BufferCount, int BufferSize)
return Enumerable.Range(0, BufferCount)
.Select(i => Enumerable.Range(0, BufferSize)
.Select(j => j * BufferCount + i).ToArray()).ToArray();
[Benchmark]
[ArgumentsSource(nameof(MemoryNumbers))]
public void InterleaveMemorySpan(Memory<int>[] data)
var rows = data.First().Length;
for (int i = 0; i < rows; i++)
for (int j = 0; j < data.Length; j++)
act(data[j].Span[i]);
[Benchmark]
[ArgumentsSource(nameof(MemoryNumbers))]
public unsafe void UnsafeInterleaveMemory(Memory<int>[] data)
var dataBuffers = stackalloc int*[data.Length];
Pin(data.AsSpan(), 0);
void Pin(Span<Memory<int>> buffers, int bufferIndex)
if (buffers.Length == 0)
InterleaveMemory(data.First().Length, data.Length, dataBuffers);
else
fixed (int* pData = buffers[0].Span)
dataBuffers[bufferIndex] = pData;
Pin(buffers.Slice(1), bufferIndex + 1);
void InterleaveMemory(int rows, int columns, int** dataSpans)
for (int i = 0; i < rows; i++)
for (int j = 0; j < columns; j++)
act(dataSpans[j][i]);
[Benchmark]
[ArgumentsSource(nameof(ArrayNumbers))]
public void InterleaveArray(int[][] data)
var rows = data.First().Length;
for (int i = 0; i < rows; i++)
for (int j = 0; j < data.Length; j++)
act(data[j][i]);
public IEnumerable<int[][]> ArrayNumbers()
yield return CreateBuffers(16, 32 * 1024);
public IEnumerable<Memory<int>[]> MemoryNumbers()
yield return CreateBuffers(16, 32 * 1024).Select(x => x.AsMemory()).ToArray();
【讨论】:
以上是关于如何表示 Span<T> 列表/数组的主要内容,如果未能解决你的问题,请参考以下文章
如何将 C# 字符串转换为 Span<char>? (跨度<T>)