[Update: Span<T>] - Evitando alocações de memória ao ler arquivos textos

12/4/2017 12:05:00 AM By Felipe Pessoto

Com o release de hoje do Visual Studio 15.5, fiz uma versão utilizando Span<T>, ainda não é possível ver suas vantagens pois muitas APIs ainda não aceitam o ReadOnlySpan<char> no lugar de strings, o que permitiria por exemplo chamar o int.TryParse diretamente. Com isso o Span<T> traria o melhor de todas as soluções apresentadas, a simplicidade do Substring, com a performance dos ponteiros, sem utilizar o unsafe.

Ainda assim o Span<T> mostra que sua performance foi a melhor entre os métodos avaliados, sem alocar praticamente nenhuma memória:

[Benchmark]
public void Read_ResultSpan()
{
    int bufferSize = GetLineSize();
    char[] buffer = new char[bufferSize];
    ReadOnlySpan<char>[] result = new ReadOnlySpan<char>[positions.Length];

    //Allocate char array of right size
    for (int i = 0; i < positions.Length; i++)
    {
        result[i] = new char[positions[i]];
    }

    using (TextReader sr = GetReader())
    {
        while (sr.Read(buffer, 0, bufferSize) > 0)
        {
            int lastIndex = 0;

            for (int i = 0; i < positions.Length; i++)
            {
                result[i] = new ReadOnlySpan<char>(buffer, lastIndex, positions[i]);
                lastIndex += positions[i];

                //int.TryParse(result[i], out int x);
            }
        }
    }
}

E o resultado final:

Method Mean Error StdDev Scaled ScaledSD Gen 0 Allocated
ReadLine_ResultSubstring 104.23 ms 2.883 ms 0.7488 ms 1.00 0.00 78700.0000 161229.46 KB
ReadLine_ResultCharArray 87.21 ms 1.725 ms 0.4482 ms 0.84 0.01 21500.0000 44043.26 KB
Read_ResultCharArray 70.48 ms 24.516 ms 6.3681 ms 0.68 0.05 - 9.6 KB
Read_ResultUseUnsafeCharPointer 107.08 ms 58.028 ms 15.0726 ms 1.03 0.13 - 9.6 KB
Read_ResultSpan 55.05 ms 4.291 ms 1.1146 ms 0.53 0.01 - 9.92 KB

O código está disponível em https://github.com/fujiy/AvoidingStringAllocation