2009-05-15 24 views
20

Tôi biết rằng ngoại lệ có hình phạt hiệu suất và nói chung là hiệu quả hơn để thử và tránh ngoại lệ hơn là thả một thử lớn/nắm bắt mọi thứ - nhưng ? Chi phí của việc chỉ tuyên bố một thử/nắm bắt là gì, ngay cả khi nó không bao giờ ném một ngoại lệ?Chi phí hoạt động của 'thử' trong C#

+8

Bạn là người duy nhất có thể trả lời câu hỏi này. Bạn là người duy nhất biết loại phần cứng và phần mềm bạn đang sử dụng, bạn là người duy nhất biết những chỉ số hiệu suất nào có liên quan đến khách hàng của bạn, v.v. Viết lên một số điểm chuẩn thực tế, thử chúng trên phần cứng thực tế, và sau đó bạn sẽ biết câu trả lời. Bất kỳ ai khác cố gắng trả lời câu hỏi cho bạn đều đoán hoặc mô tả các đặc tính hiệu suất trên máy của họ, cho khách hàng của họ, không phải của bạn. Dù bằng cách nào, đó không phải là dữ liệu bạn cần. –

+0

@Eric - Được rồi. –

Trả lời

26

Chi phí thực hiện thử rất nhỏ. Chi phí chính của xử lý ngoại lệ là nhận được dấu vết ngăn xếp và siêu dữ liệu khác, và đó là một chi phí không được thanh toán cho đến khi bạn thực sự phải ném một ngoại lệ.

Nhưng điều này sẽ thay đổi theo ngôn ngữ và triển khai. Tại sao không viết một vòng lặp đơn giản trong C# và tự nó?

+1

Đúng. Hãy thử có hiệu quả miễn phí vì nó về cơ bản được xử lý bởi siêu dữ liệu thực sự chỉ được kiểm tra khi ngoại lệ thực sự được ném. –

5

Một câu nói phổ biến là trường hợp ngoại lệ là đắt khi họ bị bắt - không ném. Điều này là do hầu hết thu thập siêu dữ liệu ngoại lệ (chẳng hạn như nhận dấu vết ngăn xếp, v.v.) chỉ thực sự xảy ra ở phía bên cố gắng (không phải ở bên ném).

Bỏ liên kết chồng thực sự là khá nhanh - CLR đi lên ngăn xếp cuộc gọi và chỉ chú ý đến các khối cuối cùng mà nó tìm thấy; không có điểm nào trong một khối thử cuối cùng thuần túy thực hiện nỗ lực thời gian chạy để 'hoàn thành' một ngoại lệ (đó là siêu dữ liệu, v.v.). Từ những gì tôi nhớ, bất kỳ thử-catches với các bộ lọc (chẳng hạn như "bắt (FooException) {}") cũng đắt tiền - ngay cả khi họ không làm bất cứ điều gì với ngoại lệ.

tôi sẽ liên doanh để nói rằng một phương pháp (gọi nó là CatchesAndRethrows) với khối sau:

try 
{ 
    ThrowsAnException(); 
} 
catch 
{ 
    throw; 
} 

Có thể dẫn đến một đi bộ ngăn xếp nhanh hơn trong một phương pháp - ví dụ như:

try 
{ 
    CatchesAndRethrows(); 
} 
catch (Exception ex) // The runtime has already done most of the work. 
{ 
    // Some fancy logic 
} 

Một số số điện thoại:

With: 0.13905ms 
Without: 0.096ms 
Percent difference: 144% 

Đây là điểm chuẩn tôi đã chạy (nhớ, chế độ phát hành - chạy không có deb ug):

static void Main(string[] args) 
    { 
     Stopwatch withCatch = new Stopwatch(); 
     Stopwatch withoutCatch = new Stopwatch(); 

     int iterations = 20000; 

     for (int i = 0; i < iterations; i++) 
     { 
      if (i % 100 == 0) 
      { 
       Console.Write("{0}%", 100 * i/iterations); 
       Console.CursorLeft = 0; 
       Console.CursorTop = 0; 
      } 

      CatchIt(withCatch, withoutCatch); 
     } 

     Console.WriteLine("With: {0}ms", ((float)(withCatch.ElapsedMilliseconds))/iterations); 
     Console.WriteLine("Without: {0}ms", ((float)(withoutCatch.ElapsedMilliseconds))/iterations); 
     Console.WriteLine("Percent difference: {0}%", 100 * withCatch.ElapsedMilliseconds/withoutCatch.ElapsedMilliseconds); 
     Console.ReadKey(true); 
    } 

    static void CatchIt(Stopwatch withCatch, Stopwatch withoutCatch) 
    { 
     withCatch.Start(); 

     try 
     { 
      FinallyIt(withoutCatch); 
     } 
     catch 
     { 
     } 

     withCatch.Stop(); 
    } 

    static void FinallyIt(Stopwatch withoutCatch) 
    { 
     try 
     { 
      withoutCatch.Start(); 
      ThrowIt(withoutCatch); 
     } 
     finally 
     { 
      withoutCatch.Stop(); 
     } 
    } 

    private static void ThrowIt(Stopwatch withoutCatch) 
    { 
     throw new NotImplementedException(); 
    } 
+1

Tôi nghĩ rằng OP hỏi về tác động hiệu suất khi ngoại lệ KHÔNG được ném. – Shimmy

7

Thực ra, một vài tháng trước tôi đã tạo ứng dụng web ASP.NET và tôi vô tình gói một khối try/catch với vòng lặp rất dài. Mặc dù vòng lặp không tạo ra mọi ngoại lệ, nó đã mất quá nhiều thời gian để hoàn thành. Khi tôi quay trở lại và thấy thử/bắt được bọc bởi vòng lặp, tôi đã làm nó theo cách khác xung quanh, tôi quấn vòng lặp trong khối try/catch. Hiệu suất cải thiện LOT. Bạn có thể tự mình thử điều này: làm điều gì đó như:

int total; 

DateTime startTime = DateTime.Now; 

for(int i = 0; i < 20000; i++) 
{ 
try 
{ 
total += i; 
} 
catch 
{ 
// nothing to catch; 
} 
} 

Console.Write((DateTime.Now - startTime).ToString()); 

Và sau đó lấy khối thử/nắm bắt. Bạn sẽ thấy một sự khác biệt lớn!

+11

Hmmm. Tôi chỉ cố gắng này trên. Net 2.0 (sử dụng một 'Đồng hồ bấm giờ '). 50000 thử nghiệm của 20000 lặp lặp lại mất 4184ms mà không có 'try-catch', 4363ms với' try-catch'. Đó là một sự khác biệt cực kỳ nhỏ. Sự khác biệt như vậy sẽ thậm chí còn ít rõ ràng hơn nếu mỗi lần lặp lại thực sự làm điều gì đó ngoài một hoạt động bổ sung đơn giản. Tôi nhấn các kết quả tương tự có và không cần gỡ lỗi. – Brian

4

Để xem chi phí thực sự là bao nhiêu, bạn có thể chạy mã bên dưới. Nó có một mảng hai chiều đơn giản và tạo ra các tọa độ ngẫu nhiên nằm ngoài phạm vi. Nếu ngoại lệ của bạn chỉ xảy ra một lần, tất nhiên bạn sẽ không nhận thấy nó. Ví dụ của tôi được thực hiện để nhấn mạnh những gì nó sẽ có nghĩa là khi làm điều này vài nghìn lần, và những gì bắt một ngoại lệ vs thực hiện một bài kiểm tra đơn giản sẽ giúp bạn tiết kiệm.

 const int size = 1000; 
     const int maxSteps = 100000; 

     var randomSeed = (int)(DateTime.UtcNow - new DateTime(1970,1,1,0,0,0).ToLocalTime()).TotalMilliseconds; 
     var random = new Random(randomSeed); 
     var numOutOfRange = 0; 
     var grid = new int[size,size]; 
     var stopwatch = new Stopwatch(); 
     Console.WriteLine("---Start test with exception---"); 
     stopwatch.Reset(); 
     stopwatch.Start(); 
     for (int i = 0; i < maxSteps; i++) 
     { 
      int coord = random.Next(0, size * 2); 
      try 
      { 
       grid[coord, coord] = 1; 
      } 
      catch (IndexOutOfRangeException) 
      { 
       numOutOfRange++; 
      } 
     } 
     stopwatch.Stop(); 
     Console.WriteLine("Time used: " + stopwatch.ElapsedMilliseconds + "ms, Number out of range: " + numOutOfRange); 
     Console.WriteLine("---End test with exception---"); 

     random = new Random(randomSeed); 

     stopwatch.Reset(); 
     Console.WriteLine("---Start test without exception---"); 
     numOutOfRange = 0; 
     stopwatch.Start(); 
     for (int i = 0; i < maxSteps; i++) 
     { 
      int coord = random.Next(0, size * 2); 
      if (coord >= grid.GetLength(0) || coord >= grid.GetLength(1)) 
      { 
       numOutOfRange++; 
       continue; 
      } 
      grid[coord, coord] = 1; 
     } 
     stopwatch.Stop(); 
     Console.WriteLine("Time used: " + stopwatch.ElapsedMilliseconds + "ms, Number out of range: " + numOutOfRange); 
     Console.WriteLine("---End test without exception---"); 
     Console.ReadLine(); 

Ví dụ đầu ra của mã này:

---Start test with exception--- 
Time used: 3228ms, Number out of range: 49795 
---End test with exception--- 
---Start test without exception--- 
Time used: 3ms, Number out of range: 49795 
---End test without exception--- 
Các vấn đề liên quan