如何表示Span <t>列表/数组

时间:2018-08-13 19:02:38

标签: c# c#-7.2

我想插入几个Memory / Span缓冲区。是否可以在不重复访问内部循环中的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]);
        }
    }
}

1 个答案:

答案 0 :(得分:0)

我没有找到一种表示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();
    }
}