Почему встроенные классы ввода-вывода С# быстрее, чем самодельные?

Когда я решил сделать свою собственную реализацию Java ByteBuffer в С#, я думал, что это будет быстрее, чем MemoryStream + BinaryWriter/BinaryReader. Я просмотрел их источник через ILSpy, и было много вызовов методов проверки и вспомогательных методов, в то время как в моей реализации я напрямую работаю с базовым массивом байтов. Но я был очень удивлен, когда тесты показали, что вызовы методов тяжелых встроенных классов почти в два раза быстрее, чем вызовы моих световых методов.

Например:

public void WriteBytes(Byte[] buffer, Int32 offset, Int32 count)
{
    this.EnsureFreeSpace(count);

    Buffer.BlockCopy(buffer, offset, this.buffer, this.position, count);

    this.position += count;
    if (this.length < this.position)
    {
        this.length = this.position;
    }
}

public void ReadBytes(Byte[] buffer, Int32 offset, Int32 count)
{
    this.EnsureDataExist(count);

    Buffer.BlockCopy(this.buffer, this.position, buffer, offset, count);

    this.position += count;
}

private void EnsureFreeSpace(Int32 count)
{
    if (this.buffer.Length - this.position < count)
    {
        throw new InvalidOperationException();
    }
}

private void EnsureDataExist(Int32 count)
{
    if (this.length - this.position < count)
    {
        throw new InvalidOperationException();
    }
}

~ 1,5-2 раза медленнее, чем

memoryStream.Write(...)
memoryStream.Read(...)

в этих простых тестах

Byte[] temp = new byte[64];
stopWatch.Restart();
for (int i = 0; i < 100000; i++)
{
    ms.Write(temp, 0, temp.Length);
    ms.Position = 0;
    ms.Read(temp, 0, temp.Length);
    ms.Position = 0;
}
stopWatch.Stop();
Console.WriteLine(stopWatch.ElapsedMilliseconds);

stopWatch.Restart();
for (int i = 0; i < 100000; i++)
{
    mb.WriteBytes(temp, 0, temp.Length);
    mb.Position = 0;
    mb.ReadBytes(temp, 0, temp.Length);
    mb.Position = 0;
}
stopWatch.Stop();
Console.WriteLine(stopWatch.ElapsedMilliseconds);

Почему?

Во всех тестах была включена оптимизация. В режиме отладки средняя разница была, как я сказал, ~ 1,7 раза. В режиме Release ~ 1,3 раза меньше, но все же там.

ИЗМЕНИТЬ Благодаря советам я обнаружил, что вне Visual Studio мой код в несколько раз быстрее или, по крайней мере, так же быстро, как и встроенный код. Итак, теперь вопрос в том, почему это происходит?

Ответ 1

Я считаю, что вы не можете проверить свою производительность правильно. Эта тема была рассмотрена несколько раз раньше, и я нахожу эту серию блога Эриком Липпертом очень поучительной: http://tech.pro/blog/1293/c-performance-benchmark-mistakes-part-one

В качестве ярлыка сделайте следующее: поместите весь тестовый код внутри цикла for и выполните несколько раз, сравните вывод и всегда отбросьте первый результат.