2009-12-16 22 views
9

Trong khi phát triển ứng dụng của tôi tôi đã xem qua một số công cụ so sánh ở đây là nó:Đó là so sánh nhanh: Convert.ToInt32 (stringValue) == intValue hoặc stringValue == intValue.ToString()

string str = "12345"; 
    int j = 12345; 
    if (str == j.ToString()) 
    { 
     //do my logic 
    } 

Tôi đã suy nghĩ rằng những thứ trên cũng có thể được thực hiện với:

string str = "12345"; 
    int j = 12345; 
    if (Convert.ToInt32(str) == j) 
    { 
     //do my logic 
    } 

Vì vậy, tôi đã phát triển một số mẫu mã để kiểm tra về hiệu suất cái nào là tốt hơn

 var iterationCount = 1000000; 
     var watch = new Stopwatch(); 
     watch.Start(); 
     string str = "12345"; 
     int j = 12345; 
     for (var i = 0; i < iterationCount; i++) 
     { 
      if (str == j.ToString()) 
      { 
       //do my logic 
      } 
     } 
     watch.Stop(); 

Và điều thứ hai:

var iterationCount = 1000000; 
    var watch = new Stopwatch(); 
    watch.Start(); 
    string str = "12345"; 
    int j = 12345; 
    for (var i = 0; i < iterationCount; i++) 
    { 
     if (Convert.ToInt32(str) == j) 
     { 
      //do my logic 
     } 
    } 
    watch.Stop(); 

Khi chạy hai thử nghiệm trên tôi thấy các thử nghiệm trên đã cho gần hết thời gian trôi qua. Tôi muốn thảo luận cái nào là cách tiếp cận tốt hơn? Và có cách tiếp cận nào khác tốt hơn hai phương pháp trên không?

Trả lời

12

Kiểm tra của bạn về cơ bản là thiếu sót. Trình biên dịch và thời gian chạy là những con thú thực sự thông minh và sẽ tối ưu hóa mã cả lúc biên dịch và thời gian chạy (JIT-ing). Trong trường hợp này, bạn đang làm cùng một điều mỗi lần sẽ được phát hiện bởi trình biên dịch và được tối ưu hóa, do đó thời gian sẽ giống nhau cho mỗi phương pháp.

Hãy thử phiên bản này (tôi chỉ có Net 2.0, vì thế mà thay đổi nhỏ):

using System; 
using System.Collections.Generic; 
using System.Text; 
using System.Diagnostics; 

namespace ToStringTest 
{ 
    class Program 
    { 
     const int 
      iterationCount = 1000000; 

     static TimeSpan Test1() 
     { 
      Stopwatch watch = new Stopwatch(); 
      watch.Start(); 
      string str = "12345"; 
      int j = 12345; 
      for (int i = 0; i < iterationCount; i++) 
      { 
       if (str == i.ToString()) 
       { 
        //do my logic 
       } 
      } 
      watch.Stop(); 
      return watch.Elapsed; 
     } 

     static TimeSpan Test2() 
     { 
      Stopwatch watch = new Stopwatch(); 
      watch.Start(); 
      string str = "12345"; 
      int j = 12345; 
      for (int i = 0; i < iterationCount; i++) 
      { 
       if (Convert.ToInt32(i) == j) 
       { 
        //do my logic 
       } 
      } 
      watch.Stop(); 
      return watch.Elapsed; 
     } 

     static void Main(string[] args) 
     { 
      Console.WriteLine("ToString = " + Test1().TotalMilliseconds); 
      Console.WriteLine("Convert = " + Test2().TotalMilliseconds); 
     } 
    } 
} 

và bạn sẽ thấy một sự khác biệt rất lớn. Một là hai đơn đặt hàng của cường độ nhanh hơn so với khác. Và nó thực sự là rõ ràng đó là một trong đó.

Bạn cần biết những hoạt động khác nhau đang hoạt động để biết nhanh hơn về cơ bản.

Chuyển đổi một chuỗi đến một int yêu cầu sau đây:

total = 0 
for each character in string 
    total = total * 10 + value of charater 

và ToString yêu cầu:

string = "" 
while value != 0 
    string.AddToFront value % 10 
    value /= 10 

Phép nhân là xa dễ dàng hơn, và nhanh hơn, cho một CPU để làm hơn là phân chia. Với sự lựa chọn của một thuật toán với rất nhiều nhân với một thuật toán với rất nhiều phân chia, luôn luôn đi cho các cựu vì nó sẽ luôn luôn được nhanh hơn.

Sau đó, có so sánh, so sánh int - int rất đơn giản, tải từng giá trị vào sổ đăng ký và so sánh - một vài hướng dẫn máy và bạn đã hoàn tất. Một so sánh giữa hai chuỗi yêu cầu kiểm tra từng ký tự trong chuỗi một tại một thời điểm - trong ví dụ bạn đã cho nó là 5 byte (một int có thể là 4 byte), đó là nhiều truy cập bộ nhớ hơn.

2

Nếu hiệu suất gần giống hệt nhau, hãy sử dụng phiên bản dễ đọc hơn.

Cá nhân, tôi tìm cách tiếp cận .ToString() để dễ hiểu hơn và ít dễ bị các vấn đề truyền có thể xảy ra mà cách tiếp cận khác có.

6

Tôi thích i.ToString() == str vì không có gì đảm bảo rằng Convert.ToInt32(str) không thành công.

+3

Nếu "000123"! = 123, điều này chắc chắn tốt hơn. –

3

Yikes, bạn hiển thị logic miền của mình như đang ở bên trong vòng lặp định cấu hình để bạn không thử nghiệm sự khác biệt về thời gian giữa các phiên bản mã ConvertToString của mã; bạn đã thử nghiệm thời gian kết hợp của chuyển đổi cộng với việc thực hiện logic nghiệp vụ của bạn. Nếu logic nghiệp vụ của bạn chậm và thống trị thời gian chuyển đổi, tất nhiên bạn sẽ thấy cùng một thời điểm trong mỗi phiên bản.

Bây giờ, với điều đó ngoài con đường, thậm chí đáng lo ngại về điều này cho đến khi bạn biết rằng đó là một nút cổ chai hiệu suất là tối ưu hóa sớm. Đặc biệt, nếu thực thi logic miền của bạn thống trị thời gian chuyển đổi, sự khác biệt giữa hai miền sẽ không bao giờ quan trọng. Vì vậy, chọn một trong đó là dễ đọc nhất.

Giờ đây, để sử dụng phiên bản nào: Bạn cần bắt đầu bằng cách chỉ định chính xác những gì bạn đang thử nghiệm. Đầu vào của bạn là gì? "007" có bao giờ là đầu vào không? Có phải "007" khác với số nguyên 7 không? "1.024" có bao giờ là đầu vào không? Có những lo ngại về bản địa hóa không?

+0

Tôi không thử nghiệm với logic miền trong hồ sơ của tôi, nó chỉ là bình luận được viết bên trong nó, như tôi đã chỉ ra. – Raghav

+0

Bạn hiển thị '// làm logic của tôi'. Mọi người sẽ giải thích rằng khi bạn đang làm logic của bạn nhưng không muốn cung cấp cho chúng tôi các chi tiết của nó, không phải là bạn nhận xét ra logic. Để làm rõ, bạn nên viết bài kiểm tra dưới dạng bool b = Convert.ToInt32 (str) == j; 'vv – jason

+0

@Raghav Frameer: ​​Hơn nữa, ngay cả khi bạn đã kiểm tra hiệu suất của hai phương pháp mà không thực thi logic miền của bạn, điểm của tôi vẫn là viết tắt: đừng lo lắng về điều này cho đến khi bạn biết đó là tắc nghẽn hiệu suất. Thay vào đó, hãy chỉ định đầy đủ những gì bạn đang cố gắng thực hiện và viết mã có thể đọc được duy nhất dễ thực hiện nhất. – jason

0

Vâng cho người mới bắt đầu người đầu tiên chuyển đổi int thành một chuỗi sẽ không ném một lỗi nếu chuỗi int được so sánh không chuyển đổi thành int.

Nếu bạn đang thực hiện nhiều thử nghiệm trong một đợt chuyển đổi thành chuỗi sẽ loại bỏ vấn đề có thể có ngoại lệ ném, vì lỗi chuyển đổi. Việc tăng các ngoại lệ cần có thời gian và sẽ làm chậm bài kiểm tra thứ hai.

13

Vâng - hiệu suất không phải là điều duy nhất quan trọng.

Bạn nên hỏi xem bạn có muốn so sánh giá trị thực tế hay chỉ đại diện cho số đó.

Lấy ví dụ sau: Có phải "00001" bằng 1 không? Nếu bạn muốn nó chuyển đổi chuỗi thành int bằng cách sử dụng Int.TryParse kết hợp và sau đó so sánh chúng.

Có thể có những khác biệt khác, quá tùy thuộc vào cài đặt cục bộ. Có thể người dùng đã đặt thành định dạng số như "1.000.000" - nếu bạn so sánh chuỗi đó với 1000000.ToString(), kết quả sẽ là sai.

2

Ngữ nghĩa có một chút khác biệt. "01" == 1.ToString()false, 1 == Convert.ToInt32("01")đúng.

Nếu việc phân tích cú pháp có thể sai (Chuỗi không phải là số hợp lệ) thì Int32.TryParse nhanh hơn sử dụng Convert.ToInt32().

0

Được rồi, tôi tiếp tục di chuyển về phía trước một bước và thử nghiệm theo cách này:

int j = 123; 
    for (var i = 0; i < iterationCount; i++) 
    { 
     j.ToString(); 
    } 

thứ hai: chuỗi str = "123";

 for (var i = 0; i < iterationCount; i++) 
     { 
      Convert.ToInt32(str); 
     } 

Trong trường hợp này tôi thấy mọi thời gian thứ hai hoạt động tốt hơn một chút. Trong trường hợp của tôi, con số sẽ chỉ là 100000 chứ không phải dưới dạng 100.000. Ý kiến ​​của bạn về thử nghiệm này mà tôi đã làm trong bài đăng này ??

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