Weiß jemand, warum C# (.NET) StartsWith Funktion ist erheblich langsamer als IsPrefix?Warum ist Funktion in C# schneller als Startswith?
Antwort
ich denke, es meistens ist das Abrufen der aktuellen Kultur des Threads.
Wenn Sie Marc-Test ändern, um diese Form von String.StartsWith
zu verwenden:
Stopwatch watch = Stopwatch.StartNew();
CultureInfo cc = CultureInfo.CurrentCulture;
for (int i = 0; i < LOOP; i++)
{
if (s1.StartsWith(s2, false, cc)) chk++;
}
watch.Stop();
Console.WriteLine(watch.ElapsedMilliseconds + "ms; chk: " + chk);
es kommt ein gutes Stück näher.
Wenn Sie s1.StartsWith(s2, StringComparison.Ordinal)
verwenden, ist es viel schneller als mit CompareInfo.IsPrefix
(abhängig von der CompareInfo
natürlich). Auf meiner Box sind die Ergebnisse (nicht wissenschaftlich):
- s1.StartsWith (s2): 6914ms
- s1.StartsWith (s2, falsch, Kultur): 5568ms
- compare.IsPrefix (s1, s2): 5200ms
- s1.StartsWith (s2, StringComparison.Ordinal): 1393ms
Offensichtlich ist das, weil es wirklich nur an jedem Punkt 16 Bit-Integer Vergleich, das ist ziemlich billig. Wenn Sie nicht wollen kultursensitive Überprüfung, und Leistung ist Ihnen besonders wichtig, das ist die Überladung, die ich verwenden würde.
StartsWith Aufrufe IsPrefix intern. Es weist Kulturinformationen vor dem Aufruf von IsPrefix zu.
Gute Frage; für einen Test, die ich erhalten:
9156ms; chk: 50000000
6887ms; chk: 50000000
Prüfstand:
using System;
using System.Diagnostics;
using System.Globalization;
class Program
{
static void Main()
{
string s1 = "abcdefghijklmnopqrstuvwxyz", s2 = "abcdefg";
const int LOOP = 50000000;
int chk = 0;
Stopwatch watch = Stopwatch.StartNew();
for (int i = 0; i < LOOP; i++)
{
if (s1.StartsWith(s2)) chk++;
}
watch.Stop();
Console.WriteLine(watch.ElapsedMilliseconds + "ms; chk: " + chk);
chk = 0;
watch = Stopwatch.StartNew();
CompareInfo ci = CultureInfo.CurrentCulture.CompareInfo;
for (int i = 0; i < LOOP; i++)
{
if (ci.IsPrefix(s1, s2)) chk++;
}
watch.Stop();
Console.WriteLine(watch.ElapsedMilliseconds + "ms; chk: " + chk);
}
}
Überprüfen Sie die Quelle von IsPrefix. Die Sache ist - in einigen Fällen wird es langsamer sein als StartsWith
, nur weil es StartsWith tatsächlich verwendet und wenig mehr Operationen ausführt.
[System.Security.SecuritySafeCritical] // auto-generated
public unsafe virtual bool IsPrefix(String source, String prefix, CompareOptions options)
{
if (source == null || prefix == null) {
throw new ArgumentNullException((source == null ? "source" : "prefix"),
Environment.GetResourceString("ArgumentNull_String"));
}
Contract.EndContractBlock();
int prefixLen = prefix.Length;
if (prefixLen == 0)
{
return (true);
}
if (options == CompareOptions.OrdinalIgnoreCase)
{
return source.StartsWith(prefix, StringComparison.OrdinalIgnoreCase);
}
if (options == CompareOptions.Ordinal)
{
return source.StartsWith(prefix, StringComparison.Ordinal);
}
if ((options & ValidIndexMaskOffFlags) != 0) {
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidFlag"), "options");
}
// to let the sorting DLL do the call optimization in case of Ascii strings, we check if the strings are in Ascii and then send the flag RESERVED_FIND_ASCII_STRING to
// the sorting DLL API SortFindString so sorting DLL don't have to check if the string is Ascii with every call to SortFindString.
return (InternalFindNLSStringEx(
m_dataHandle, m_handleOrigin, m_sortName,
GetNativeCompareFlags(options) | Win32Native.FIND_STARTSWITH | ((source.IsAscii() && prefix.IsAscii()) ? RESERVED_FIND_ASCII_STRING : 0),
source, source.Length, 0, prefix, prefix.Length) > -1);
}