Why is my StringReader 50us slower than a .NET StringReader?

In my test, I created a string with 32000 characters. After running the BCL test again, StringReader ran sequentially at 350us, and mine at 400us. What secrets do they hide?

Test:

private void SpeedTest()
{
    String r = "";
    for (int i = 0; i < 1000; i++)
    {
        r += Randomization.GenerateString();
    }

    StopWatch s = new StopWatch();
    s.Start();
    using (var sr = new System.IO.StringReader(r))
    {               
        while (sr.Peek() > -1)
        {
            sr.Read();
        }
    }

    s.Stop();
    _Write(s.Elapsed);
    s.Reset();
    s.Start();

    using (var sr = new MagicSynthesis.StringReader(r))
    {               
        while (sr.PeekNext() > Char.MinValue)
        {
            sr.Next();
        }               
    }

    s.Stop();
    _Write(s.Elapsed);
}

Code:

public unsafe class StringReader : IDisposable
{
    private Char* Base;
    private Char* End;
    private Char* Current;
    private const Char Null = '\0';


    /// <summary></summary>
    public StringReader(String s)
    {
        if (s == null)
            throw new ArgumentNullException("s");           

        Base = (Char*)Marshal.StringToHGlobalUni(s).ToPointer();
        End = (Base + s.Length);
        Current = Base;
    }


    /// <summary></summary>
    public Char Next()
    {
        return (Current < End) ? *(Current++) : Null; 
    }

    /// <summary></summary>
    public String Next(Int32 length)
    {
        String s = String.Empty;

        while (Current < End && length > 0)
        {
            length--;
            s += *(Current++);
        }

        return s;
    }

    /// <summary></summary>
    public Char PeekNext()
    {
        return *(Current); 
    }

    /// <summary></summary>
    public String PeekNext(Int32 length)
    {
        String s = String.Empty;
        Char* a = Current;

        while (Current < End && length > 0)
        {
            length--;
            s += *(Current++);
        }

        Current = a;

        return s;
    }


    /// <summary></summary>
    public Char Previous()
    {
        return ((Current > Base) ? *(--Current) : Null);
    }

    /// <summary></summary>
    public Char PeekPrevious()
    {
        return ((Current > Base) ? *(Current - 1) : Null);
    }


    /// <summary></summary>
    public void Dispose()
    {
        Marshal.FreeHGlobal(new IntPtr(Base));          
    }
}
+3
source share
5 answers

I bet that Marshal.StringToHGlobalUni()they Marshal.FreeHGlobal(new IntPtr(Base))have a lot in common with the differences. I'm not sure how StringReader manages the string, but I'm sure that it does not copy it to unmanaged memory.

Looking at the StringReader.Read () method in Reflector, this shows:

public override int Read()
{
    if (this._s == null)
    {
        __Error.ReaderClosed();
    }
    if (this._pos == this._length)
    {
        return -1;
    }
    return this._s[this._pos++];
}

The contractor is also fair:

public StringReader(string s)
{
    if (s == null)
    {
        throw new ArgumentNullException("s");
    }
    this._s = s;
    this._length = (s == null) ? 0 : s.Length;
}

, , StringReader .

Edit
Next() , , , . StringReader.Read() _pos , , , .

+4
+4

+4

, , StringReader.Read():

public override int Read()
{
    if (this._s == null)
    {
        __Error.ReaderClosed();
    }
    if (this._pos == this._length)
    {
        return -1;
    }
    return this._s[this._pos++];
}

. , , .

+2

StringReader, , - , ? , .

, BCL. GAC'd , , .

+2

Source: https://habr.com/ru/post/1717308/


All Articles