首页 > 解决方案 > 使用 Span 的性能解析文本文件

问题描述

我正在尝试Span<T>利用.NETCore 2.2来提高从文本文件中解析文本的性能。文本文件包含多行连续的数据,每行将被拆分为字段,然后每个字段都映射到一个数据类。

最初,解析例程使用传统的方法StreamReader来读取每一行,然后使用Substring从该行复制各个字段。

根据我所读到的内容(在 MSDN 上),除其他外,使用Span<T>withSlice应该更有效地执行更少的数据分配,而是byte[]传递指向数组的指针并对其进行操作。

经过一些实验,我比较了 3 种解析文件的方法,并使用 BenchmarkDotNet 来比较结果。我发现,当使用 解析文本文件中的单行时Span,平均执行时间和分配的内存确实要少得多。到目前为止,一切都很好。但是,当从文件中解析多于一行时,性能提升很快就会消失,以至于几乎可以忽略不计,即使是从少到 50 行也是如此。

基准测试结果

我确定我一定错过了什么。某些东西似乎超过了Span.

性能最好的方法WithSpan_StringFirst如下所示:

private static byte[] _filecontent;
private const int ROWSIZE = 252;
private readonly Encoding _encoding = Encoding.ASCII;

public void WithSpan_StringFirst()
{
    var buffer1 = new Span<byte>(_filecontent).Slice(0, RowCount * ROWSIZE);
    var buffer = _encoding.GetString(buffer1).AsSpan();

    int cursor = 0;
    for (int i = 0; i < RowCount; i++)
    {
        var row = buffer.Slice(cursor, ROWSIZE);
        cursor += ROWSIZE;
        Foo.ReadWithSpan(row);
    }
}

[Params(1, 50)]
public int RowCount { get; set; }

实施Foo.ReadWithSpan

public static Foo ReadWithSpan(ReadOnlySpan<char> buffer) => new Foo
{
    Field1 = buffer.Read(0, 2),
    Field2 = buffer.Read(3, 4),
    Field3 = buffer.Read(5, 6),
    // ...
    Field30 = buffer.Read(246, 249)
};

public static string Read(this ReadOnlySpan<char> input, int startIndex, int endIndex)
{
    return new string(input.Slice(startIndex, endIndex - startIndex));
}

对于任何反馈,我们都表示感谢。我在 github 上发布了一个完整的工作示例。

标签: c#

解决方案


推荐阅读