2017-08-24 14 views
6

Tôi chạy vào một hiệu suất lạ "tạo tác" với String.StartsWith.Hiệu suất của String.StartsBằng cách sử dụng StringComparison.OrdinalIgnoreCase

Có vẻ như String.StartsWith sử dụng OrdinalIgnoreCase nhanh hơn sử dụng String.StartsWith mà không chỉ định StringComparison. (2-4x nhanh hơn)

Tuy nhiên, việc kiểm tra bình đẳng sẽ nhanh hơn khi sử dụng String.Equals không có StringComparison so với khi sử dụng OrdinalIgnoreCase. (Mặc dù tất cả đều có cùng tốc độ)

Câu hỏi đặt ra là tại sao? Tại sao họ thực hiện khác nhau trong hai trường hợp?

Đây là mã tôi đã sử dụng:

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

    } 

Trả lời

1

Vì vậy, không giống như String.StartsWith (như được chỉ ra bởi Enigmativity), String.Equa ls không sử dụng bất kỳ StringComparison theo mặc định nếu không có gì được chỉ định. Thay vào đó, nó sử dụng triển khai tùy chỉnh của riêng mình, bạn có thể xem tại liên kết bên dưới: https://referencesource.microsoft.com/#mscorlib/system/string.cs,11648d2d83718c5e

Điều này nhanh hơn so với So sánh thông thường. Nhưng cần lưu ý rằng nếu bạn muốn nhất quán giữa các so sánh, hãy sử dụng cả String.Equals và String.StartsWith với StringComparison, hoặc chúng không hoạt động như bạn mong đợi.

2

Dường như việc thực hiện là khác nhau trong 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"); 
     } 

Việc so sánh mặc định sử dụng là:

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

Tôi có thể hiểu tại sao nó sẽ nhanh hơn với Ordinal - Tôi không hiểu tại sao String.Equals hoạt động khác ... – MineR

+0

OK, vì vậy khi nhìn vào String.Equals, nó không thực sự sử dụng StringComparison nếu không có được chỉ định - thay vào đó nó sử dụng một triển khai cụ thể. – MineR

Các vấn đề liên quan