【问题标题】:How to represent Span<T> list/array如何表示 Span<T> 列表/数组
【发布时间】: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@)

标签: c# c#-7.2


【解决方案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();
    }
}

【讨论】:

    猜你喜欢
    • 2020-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-27
    • 2021-03-06
    • 2021-10-16
    相关资源
    最近更新 更多