2017-08-24 31 views
6

我遇到了一個奇怪的表現「工件」與String.StartsWith。String.StartsWith使用StringComparison.OrdinalIgnoreCase的性能

看來String.StartsWith使用OrdinalIgnoreCase比使用String.StartsWith更快,但沒有指定StringComparison。 (快2-4倍)

但是,使用String.Equals而不使用StringComparison時,檢查等同性比使用OrdinalIgnoreCase時快。 (雖然都是大致相同的速度)

問題是爲什麼?爲什麼他們在這兩種情況下表現不同?

這裏是我使用的代碼:看來,實現不同

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); 

    } 

回答

1

所以不像String.StartsWith(正如Enigmativity指出的那樣),String.Equa如果沒有指定,ls不會使用任何StringComparison。相反,它使用自己的自定義實現,您可以在以下鏈接中看到: https://referencesource.microsoft.com/#mscorlib/system/string.cs,11648d2d83718c5e

這比序數比較稍快。

但重要的是要注意,如果您希望比較之間保持一致,請將String.Equals和String.StartsWith同時用於StringComparison,否則它們不會像您期望的那樣運行。

2

public Boolean StartsWith(String value, StringComparison comparisonType)

 switch (comparisonType) { 
      case StringComparison.CurrentCulture: 
       return CultureInfo.CurrentCulture.CompareInfo.IsPrefix(this, value, CompareOptions.None); 

      case StringComparison.CurrentCultureIgnoreCase: 
       return CultureInfo.CurrentCulture.CompareInfo.IsPrefix(this, value, CompareOptions.IgnoreCase); 

      case StringComparison.InvariantCulture: 
       return CultureInfo.InvariantCulture.CompareInfo.IsPrefix(this, value, CompareOptions.None); 

      case StringComparison.InvariantCultureIgnoreCase: 
       return CultureInfo.InvariantCulture.CompareInfo.IsPrefix(this, value, CompareOptions.IgnoreCase); 

      case StringComparison.Ordinal: 
       if(this.Length < value.Length) { 
        return false; 
       } 
       return (nativeCompareOrdinalEx(this, 0, value, 0, value.Length) == 0); 

      case StringComparison.OrdinalIgnoreCase: 
       if(this.Length < value.Length) { 
        return false; 
       } 

       return (TextInfo.CompareOrdinalIgnoreCaseEx(this, 0, value, 0, value.Length, value.Length) == 0); 

      default: 
       throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType"); 
     } 

使用默認的比較是:

#if FEATURE_CORECLR 
           StringComparison.Ordinal); 
#else 
           StringComparison.CurrentCulture); 
#endif 
+0

我可以理解爲什麼它會更快與序數 - 我只是不明白爲什麼String.Equals行爲不同... – MineR

+0

好吧,所以看着String.Equals,它實際上並沒有使用StringComparison,如果沒有指定 - 而是使用特定的實現。 – MineR