2008-09-29 28 views
30

Tôi biết nhiều về các cách xử lý văn bản phân tích thông tin khác nhau. Ví dụ: để phân tích cú pháp các số nguyên, loại hiệu suất nào có thể được mong đợi. Tôi tự hỏi nếu có ai biết về bất kỳ số liệu thống kê tốt về điều này. Tôi đang tìm kiếm một số số thực từ một người đã thử nghiệm điều này.Hiệu suất phân tích cú pháp (Nếu, TryParse, Try-Catch)

Điều nào trong số này cung cấp hiệu suất tốt nhất trong tình huống nào?

Parse(...) // Crash if the case is extremely rare .0001% 

If (SomethingIsValid) // Check the value before parsing 
    Parse(...) 

TryParse(...) // Using TryParse 

try 
{ 
    Parse(...) 
} 
catch 
{ 
    // Catch any thrown exceptions 
} 
+0

Một thời gian trở lại Jon Skeet đã làm một số điểm chuẩn cho công cụ này. Xin lỗi, tôi không có liên kết sẵn sàng - Có thể nhấn google? –

Trả lời

60

Luôn luôn sử dụng T.TryParse (string str, ra giá trị T). Ném ngoại lệ là tốn kém và nên tránh nếu bạn có thể xử lý tình huống một số ưu tiên. Sử dụng khối try-catch để "lưu" về hiệu suất (vì tỷ lệ dữ liệu không hợp lệ của bạn thấp) là lạm dụng xử lý ngoại lệ với chi phí bảo trì và thực hành mã hóa tốt. Thực hiện theo các thực hành phát triển kỹ thuật phần mềm âm thanh, viết các trường hợp thử nghiệm của bạn, chạy ứng dụng của bạn, THEN benchmark và tối ưu hóa.

"Chúng ta nên quên đi hiệu quả nhỏ, nói rằng khoảng 97% thời gian:. sớm tối ưu hóa là gốc rễ của mọi tội lỗi Tuy nhiên, chúng ta không nên bỏ qua cơ hội của chúng tôi trong đó quan trọng 3%" -Donald Knuth

Vì vậy bạn chỉ định, tùy tiện như thế nào trong các khoản tín dụng cacbon, rằng hiệu suất của try-catch là tồi tệ hơn và rằng hiệu suất của TryParse là tốt hơn. Chỉ sau khi chúng tôi đã chạy ứng dụng của chúng tôi và xác định rằng chúng tôi có một số loại chậm chạp w.r.t. chuỗi phân tích cú pháp, chúng tôi thậm chí sẽ xem xét việc sử dụng bất cứ điều gì khác hơn là TryParse.

(chỉnh sửa: kể từ khi nó xuất hiện người hỏi muốn thời gian dữ liệu đi với lời khuyên tốt, đây là dữ liệu thời gian yêu cầu)

Times cho tỷ lệ thất bại khác nhau trên 10.000 đầu vào từ người sử dụng (đối với người không tin) :

Failure Rate  Try-Catch   TryParse  Slowdown 
    0%   00:00:00.0131758 00:00:00.0120421  0.1 
10%   00:00:00.1540251 00:00:00.0087699  16.6 
20%   00:00:00.2833266 00:00:00.0105229  25.9 
30%   00:00:00.4462866 00:00:00.0091487  47.8 
40%   00:00:00.6951060 00:00:00.0108980  62.8 
50%   00:00:00.7567745 00:00:00.0087065  85.9 
60%   00:00:00.7090449 00:00:00.0083365  84.1 
70%   00:00:00.8179365 00:00:00.0088809  91.1 
80%   00:00:00.9468898 00:00:00.0088562 105.9 
90%   00:00:01.0411393 00:00:00.0081040 127.5 
100%   00:00:01.1488157 00:00:00.0078877 144.6 


/// <param name="errorRate">Rate of errors in user input</param> 
/// <returns>Total time taken</returns> 
public static TimeSpan TimeTryCatch(double errorRate, int seed, int count) 
{ 
    Stopwatch stopwatch = new Stopwatch(); 
    Random random = new Random(seed); 
    string bad_prefix = @"X"; 

    stopwatch.Start(); 
    for(int ii = 0; ii < count; ++ii) 
    { 
     string input = random.Next().ToString(); 
     if (random.NextDouble() < errorRate) 
     { 
      input = bad_prefix + input; 
     } 

     int value = 0; 
     try 
     { 
      value = Int32.Parse(input); 
     } 
     catch(FormatException) 
     { 
      value = -1; // we would do something here with a logger perhaps 
     } 
    } 
    stopwatch.Stop(); 

    return stopwatch.Elapsed; 
} 

/// <param name="errorRate">Rate of errors in user input</param> 
/// <returns>Total time taken</returns> 
public static TimeSpan TimeTryParse(double errorRate, int seed, int count) 
{ 
    Stopwatch stopwatch = new Stopwatch(); 
    Random random = new Random(seed); 
    string bad_prefix = @"X"; 

    stopwatch.Start(); 
    for(int ii = 0; ii < count; ++ii) 
    { 
     string input = random.Next().ToString(); 
     if (random.NextDouble() < errorRate) 
     { 
      input = bad_prefix + input; 
     } 

     int value = 0; 
     if (!Int32.TryParse(input, out value)) 
     { 
      value = -1; // we would do something here with a logger perhaps 
     } 
    } 
    stopwatch.Stop(); 

    return stopwatch.Elapsed; 
} 

public static void TimeStringParse() 
{ 
    double errorRate = 0.1; // 10% of the time our users mess up 
    int count = 10000; // 10000 entries by a user 

    TimeSpan trycatch = TimeTryCatch(errorRate, 1, count); 
    TimeSpan tryparse = TimeTryParse(errorRate, 1, count); 

    Console.WriteLine("trycatch: {0}", trycatch); 
    Console.WriteLine("tryparse: {0}", tryparse); 
} 
+2

Aristotle không bao giờ bị bẩn tay bằng cách chạy thử nghiệm. Cực kỳ xấu hổ. Bạn cần phải khẳng định điều gì đó rõ ràng là đúng. Đó là cách internet !!! –

+0

@chris: Tôi bị suy giảm vì lý do nào đó ... Tôi đoán sự thật là đau. – user7116

+0

Cảm ơn bạn đã thực hiện các tiêu chuẩn quickie, ngay cả khi phiên bản try-catch là sai-đầu để được với vì vậy thực tế là TryParse() là nhanh hơn thậm chí không cần phải được chứng minh ... –

6

Try-Catch sẽ luôn chậm hơn. TryParse sẽ nhanh hơn.

IF và TryParse giống nhau.

+5

Để hoàn toàn rõ ràng, Try-Catch sẽ chỉ chậm hơn nếu phân tích cú pháp không thành công; không ném/bắt một ngoại lệ không chi phí bất cứ điều gì. – technophile

+0

Có, một phần lý do tôi hỏi là vì tôi tự hỏi chi phí làm khối try-catch là gì so với có thể không làm gì cả. –

+1

Nếu lỗi không xảy ra, loại hiệu suất nào có thể được mong đợi? Đây là lý do tại sao tôi yêu cầu một số số liệu thống kê về điều này và không chỉ "Đây là một nhanh hơn" –

-3
Option 1: Will throw an exception on bad data. 
Option 2: SomethingIsValid() could be quite expensive - particularly if you are pre-checking a string for Integer parsability. 
Option 3: I like this. You need a null check afterwards, but it's pretty cheap. 
Option 4 is definitely the worst. 

xử lý ngoại lệ là tương đối đắt, vì vậy tránh nó nếu bạn có thể.

Đặc biệt, các yếu tố đầu vào kém sẽ được mong đợi, không đặc biệt, vì vậy bạn không nên sử dụng chúng cho tình huống này.

(. Mặc dù, trước khi TryParse, Nó có thể là lựa chọn tốt nhất)

+0

Đối với Lựa chọn 1 & 4: OP thực sự đang cố gắng xác định xem chi phí ném có đáng kể không khi không thể bỏ qua khả năng ném (ông ta nói 0,0001%). Tùy chọn 2 & 3 thực sự giống nhau. TryParse, đằng sau hậu trường, thực hiện chính xác những gì Option 2 làm, giả sử Option 2 không mở sqlconnections hoặc một cái gì đó kỳ lạ. Cuối cùng, Option 3 bạn không bao giờ phải kiểm tra null. Nếu bạn định thêm séc, bạn chỉ cần kiểm tra sự trở lại của lần thử. Vì vậy, trong khi tại thời điểm này bạn có một điểm số cao và có lẽ biết tất cả điều này, tôi cảm thấy nó phải được thêm vào như là rõ ràng là tại sao câu trả lời cũ này có -2 – Suamere

+0

Những gì TryParse làm: http://referencesource.microsoft.com/ # mscorlib/system/int32.cs, 325507e509229dbc – Suamere

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