Информация об изменениях

Сообщение Производительность работы со строками. Что я делаю не так? от 21.12.2016 19:08

Изменено 21.12.2016 23:06 Artem Korneev

По мотивам вот этого
Автор: Sinix
Дата: 19.04.16
поста.

  Код.
static void AssertState(bool condition, string message)
{
if (!condition)
{
throw new InvalidOperationException(message);
}
}

static void AssertState(bool condition, IFormattable message)
{
if (!condition)
{
throw new InvalidOperationException(message.ToString());
}
}

static void AssertStateMessage(bool condition, string message)
{
if (!condition)
{
throw new ArgumentException(message);
}
}

static void AssertStateMessage(bool condition, string messageFormat, params object[] args)
{
if (!condition)
{
throw new ArgumentException(string.Format(messageFormat, args));
}
}

static void AssertStateFunc(bool condition, Func<string> messageCallback)
{
if (!condition)
{
throw new InvalidOperationException(messageCallback());
}
}

static void Main(string[] args)
{
const int Count = 10 * 1000 * 1000;
Measure("Concatenation", () =>
{
for (int i = 0; i < Count; i++)
{
AssertState(true, "Message '" + i + "': " + i + "." + i + "!");
}
return Count;
});
Measure("Interpolation", () =>
{
for (int i = 0; i < Count; i++)
{
AssertState(true, $"Message '{i}':{i}.{i}!");
}
return Count;
});
Measure("String", () =>
{
for (int i = 0; i < Count; i++)
{
AssertState(true, "Message #0");
}
return Count;
});
Measure("String.Format", () =>
{
for (int i = 0; i < Count; i++)
{
AssertStateMessage(true, "Message '{0}':{0}.{0}!", i);
}
return Count;
});

Console.WriteLine();
Console.WriteLine("Done.");
}

static void Measure(string name, Func<long> callback)
{
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();

var mem = GC.GetTotalMemory(true);
var gc00 = GC.CollectionCount(0);
var gc01 = GC.CollectionCount(1);
var gc02 = GC.CollectionCount(2);

var sw = System.Diagnostics.Stopwatch.StartNew();
var result = callback();
sw.Stop();

var mem2 = GC.GetTotalMemory(false);
var gc10 = GC.CollectionCount(0);
var gc11 = GC.CollectionCount(1);
var gc12 = GC.CollectionCount(2);

var memDelta = (mem2 — mem) / 1024.0;
var gcDelta0 = gc10 — gc00;
var gcDelta1 = gc11 — gc01;
var gcDelta2 = gc12 — gc02;

Console.WriteLine(
"{0,20}: {1,5}ms, ips: {2,22:N} | Mem: {3,9:N2} kb, GC 0/1/2: {4}/{5}/{6} => {7,6}",
name, sw.ElapsedMilliseconds, result / sw.Elapsed.TotalSeconds, memDelta, gcDelta0, gcDelta1, gcDelta2, result);
}


Всё почти как в первоисточнике, разница лишь в том, что я делаю конкатенацию/форматирование с несколькими элементами, не с одним. Но результаты у меня получаются совершенно другие:

Concatenation: 7545ms, ips: 1,325,367.80 | Mem: 955.69 kb, GC 0/1/2: 1351/0/0 => 10000000
Interpolation: 7907ms, ips: 1,264,567.77 | Mem: 265.71 kb, GC 0/1/2: 968/0/0 => 10000000
String: 58ms, ips: 170,960,920.04 | Mem: 8.00 kb, GC 0/1/2: 0/0/0 => 10000000
String.Format: 303ms, ips: 32,982,759.58 | Mem: 1,058.69 kb, GC 0/1/2: 133/0/0 => 10000000

Интерполяция, получается, медленнее даже простой конкатенации. Проверял, собирая под разные фреймворке, от 4.0 до 4.6.2, плюс dotnet core, результаты примерно одинаковые.
Что я делаю не так?
По мотивам вот этого
Автор: Sinix
Дата: 19.04.16
поста.

  Код.
static void AssertState(bool condition, string message)
{
if (!condition)
{
throw new InvalidOperationException(message);
}
}

static void AssertState(bool condition, IFormattable message)
{
if (!condition)
{
throw new InvalidOperationException(message.ToString());
}
}

static void AssertStateMessage(bool condition, string message)
{
if (!condition)
{
throw new ArgumentException(message);
}
}

static void AssertStateMessage(bool condition, string messageFormat, params object[] args)
{
if (!condition)
{
throw new ArgumentException(string.Format(messageFormat, args));
}
}

static void AssertStateFunc(bool condition, Func<string> messageCallback)
{
if (!condition)
{
throw new InvalidOperationException(messageCallback());
}
}

static void Main(string[] args)
{
const int Count = 10 * 1000 * 1000;
Measure("Concatenation", () =>
{
for (int i = 0; i < Count; i++)
{
AssertState(true, "Message '" + i + "': " + i + "." + i + "!");
}
return Count;
});
Measure("Interpolation", () =>
{
for (int i = 0; i < Count; i++)
{
AssertState(true, $"Message '{i}':{i}.{i}!");
}
return Count;
});
Measure("String", () =>
{
for (int i = 0; i < Count; i++)
{
AssertState(true, "Message #0");
}
return Count;
});
Measure("String.Format", () =>
{
for (int i = 0; i < Count; i++)
{
AssertStateMessage(true, "Message '{0}':{0}.{0}!", i);
}
return Count;
});

Console.WriteLine();
Console.WriteLine("Done.");
}

static void Measure(string name, Func<long> callback)
{
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();

var mem = GC.GetTotalMemory(true);
var gc00 = GC.CollectionCount(0);
var gc01 = GC.CollectionCount(1);
var gc02 = GC.CollectionCount(2);

var sw = System.Diagnostics.Stopwatch.StartNew();
var result = callback();
sw.Stop();

var mem2 = GC.GetTotalMemory(false);
var gc10 = GC.CollectionCount(0);
var gc11 = GC.CollectionCount(1);
var gc12 = GC.CollectionCount(2);

var memDelta = (mem2 — mem) / 1024.0;
var gcDelta0 = gc10 — gc00;
var gcDelta1 = gc11 — gc01;
var gcDelta2 = gc12 — gc02;

Console.WriteLine(
"{0,20}: {1,5}ms, ips: {2,22:N} | Mem: {3,9:N2} kb, GC 0/1/2: {4}/{5}/{6} => {7,6}",
name, sw.ElapsedMilliseconds, result / sw.Elapsed.TotalSeconds, memDelta, gcDelta0, gcDelta1, gcDelta2, result);
}


Всё почти как в первоисточнике, разница лишь в том, что я делаю конкатенацию/форматирование с несколькими элементами, не с одним. Но результаты у меня получаются совершенно другие:

Concatenation: 7545ms, ips: 1,325,367.80 | Mem: 955.69 kb, GC 0/1/2: 1351/0/0 => 10000000
Interpolation: 7907ms, ips: 1,264,567.77 | Mem: 265.71 kb, GC 0/1/2: 968/0/0 => 10000000
String: 58ms, ips: 170,960,920.04 | Mem: 8.00 kb, GC 0/1/2: 0/0/0 => 10000000
String.Format: 303ms, ips: 32,982,759.58 | Mem: 1,058.69 kb, GC 0/1/2: 133/0/0 => 10000000

Интерполяция, получается, медленнее даже простой конкатенации. Проверял, собирая под разные фреймворки, от 4.0 до 4.6.2, плюс dotnet core, результаты примерно одинаковые.
Что я делаю не так?