如何表示 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&lt;int&gt;[]Span&lt;Span&lt;int&gt;&gt; 的方法,但我使用递归不安全函数通过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>)

vue里面如何让v-for循环出来的列表里面的列表click事件只对当前列表有效

如何使用 map 和 join 渲染 React 组件?

用js如何实现点击加或减 其数值做相应的改变

vue-数据列表筛选

数组 列表 拆分