Wpadłem na dziwny performance "artefakt" z String.StartsWith.Wydajność String.Starts przy użyciu StringComparison.OrdinalIgnoreCase
Wygląda na to, że String.StartsS przy użyciu OrdininalIgnoreCase jest szybszy niż użycie String.StartsWith bez określenia StringComparison. (2-4x szybciej)
Jednak sprawdzanie równości jest szybsze przy użyciu String.Equals bez StringComparison niż przy użyciu OrdininalIgnoreCase. (Chociaż wszystkie mają mniej więcej taką samą prędkość)
Pytanie brzmi: dlaczego? Dlaczego w obu przypadkach działają inaczej?
Oto kod używałem:
public static void Test()
{
var options = new[] { "asd/klfe", "qer/jlkfe", "p33/ji", "fkjlfe", "asd/23", "bleash", "quazim", "ujv/3", "jvd/kfl" };
Random r;
const int trialSize = 100000;
const int trials = 1000;
Stopwatch swEqOp = new Stopwatch();
Stopwatch swEq = new Stopwatch();
Stopwatch swEqOrdinal = new Stopwatch();
Stopwatch swStartsWith = new Stopwatch();
Stopwatch swStartsWithOrdinal = new Stopwatch();
for (int i = 0; i < trials; i++)
{
{
r = new Random(1);
swEqOp.Start();
for (int j = 0; j < trialSize; j++)
{
bool result = options[r.Next(options.Length)] == "asd/klfe";
}
swEqOp.Stop();
}
{
r = new Random(1);
swEq.Start();
for (int j = 0; j < trialSize; j++)
{
bool result = string.Equals(options[r.Next(options.Length)], "asd/klfe");
}
swEq.Stop();
}
{
r = new Random(1);
swEqOrdinal.Start();
for (int j = 0; j < trialSize; j++)
{
bool result = string.Equals(options[r.Next(options.Length)], "asd/klfe", StringComparison.OrdinalIgnoreCase);
}
swEqOrdinal.Stop();
}
{
r = new Random(1);
swStartsWith.Start();
for (int j = 0; j < trialSize; j++)
{
bool result = options[r.Next(options.Length)].StartsWith("asd/");
}
swStartsWith.Stop();
}
{
r = new Random(1);
swStartsWithOrdinal.Start();
for (int j = 0; j < trialSize; j++)
{
bool result = options[r.Next(options.Length)].StartsWith("asd/",StringComparison.OrdinalIgnoreCase);
}
swStartsWithOrdinal.Stop();
}
}
//DEBUG with debugger attached. Release without debugger attached. AnyCPU both cases.
//DEBUG : 1.54 RELEASE : 1.359
Console.WriteLine("Equals Operator: " + swEqOp.ElapsedMilliseconds/1000d);
//DEBUG : 1.498 RELEASE : 1.349 <======= FASTEST EQUALS
Console.WriteLine("String.Equals: " + swEq.ElapsedMilliseconds/1000d);
//DEBUG : 1.572 RELEASE : 1.405
Console.WriteLine("String.Equals OrdinalIgnoreCase: " + swEqOrdinal.ElapsedMilliseconds/1000d);
//DEBUG : 14.234 RELEASE : 9.914
Console.WriteLine("String.StartsWith: " + swStartsWith.ElapsedMilliseconds/1000d);
//DEBUG : 7.956 RELEASE : 3.953 <======= FASTEST StartsWith
Console.WriteLine("String.StartsWith OrdinalIgnoreCase: " + swStartsWithOrdinal.ElapsedMilliseconds/1000d);
}
Mogę zrozumieć, dlaczego byłoby szybciej z porządkowe - po prostu nie rozumiem, dlaczego String.Equals zachowuje się inaczej ... – MineR
OK, więc patrząc na String.Equals, to faktycznie nie używa StringComparison, jeśli żaden nie jest określony - zamiast tego używa konkretnej implementacji. – MineR