Các khối thử / bắt có làm tổn thương hiệu suất khi ngoại lệ không được ném không?


274

Trong quá trình đánh giá mã với một nhân viên của Microsoft, chúng tôi đã bắt gặp một phần lớn mã bên trong một try{}khối. Cô và một đại diện CNTT cho rằng điều này có thể có ảnh hưởng đến hiệu suất của mã. Trong thực tế, họ đề xuất hầu hết các mã nên nằm ngoài các khối thử / bắt và chỉ nên kiểm tra các phần quan trọng. Nhân viên của Microsoft đã thêm và cho biết một tờ giấy trắng sắp tới cảnh báo chống lại các khối thử / bắt không chính xác.

Tôi đã nhìn xung quanh và thấy nó có thể ảnh hưởng đến việc tối ưu hóa , nhưng dường như chỉ áp dụng khi một biến được chia sẻ giữa các phạm vi.

Tôi không hỏi về khả năng duy trì của mã, hoặc thậm chí xử lý các trường hợp ngoại lệ đúng (mã trong câu hỏi cần bao thanh toán lại, không nghi ngờ gì). Tôi cũng không đề cập đến việc sử dụng các ngoại lệ để kiểm soát luồng, điều này rõ ràng là sai trong hầu hết các trường hợp. Đó là những vấn đề quan trọng (một số quan trọng hơn), nhưng không phải là trọng tâm ở đây.

Làm thế nào để các khối thử / bắt ảnh hưởng đến hiệu suất khi các ngoại lệ không được ném?


147
"Người sẽ hy sinh tính đúng đắn cho hiệu suất cũng không xứng đáng."
Joel Coehoorn

16
Điều đó nói rằng, sự đúng đắn không cần phải luôn luôn được hy sinh cho hiệu suất.
Dan Davies Brackett

19
Làm thế nào về sự tò mò đơn giản?
Samantha Branham

63
@Joel: Có lẽ Kobi chỉ muốn biết câu trả lời vì tò mò. Biết được hiệu suất sẽ tốt hơn hay tệ hơn không có nghĩa là anh ta sẽ làm bất cứ điều gì điên rồ với mã của mình. Không phải việc theo đuổi kiến ​​thức là vì điều tốt đẹp sao?
LukeH

6
Đây là một thuật toán tốt để biết có nên thực hiện thay đổi này hay không. Đầu tiên, đặt mục tiêu hiệu suất dựa trên khách hàng có ý nghĩa. Thứ hai, viết mã để vừa chính xác vừa rõ ràng trước. Thứ ba, kiểm tra nó chống lại mục tiêu của bạn. Thứ tư, nếu bạn đạt được mục tiêu của mình, hãy nghỉ việc sớm và đi biển. Thứ năm, nếu bạn không đạt được mục tiêu của mình, hãy sử dụng một trình lược tả để tìm mã quá chậm. Thứ sáu, nếu mã đó xảy ra quá chậm vì một trình xử lý ngoại lệ không cần thiết, chỉ sau đó loại bỏ trình xử lý ngoại lệ. Nếu không, hãy sửa mã thực sự quá chậm. Sau đó quay lại bước ba.
Eric Lippert

Câu trả lời:


203

Kiểm tra nó.

static public void Main(string[] args)
{
    Stopwatch w = new Stopwatch();
    double d = 0;

    w.Start();

    for (int i = 0; i < 10000000; i++)
    {
        try
        {
            d = Math.Sin(1);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }
    }

    w.Stop();
    Console.WriteLine(w.Elapsed);
    w.Reset();
    w.Start();

    for (int i = 0; i < 10000000; i++)
    {
        d = Math.Sin(1);
    }

    w.Stop();
    Console.WriteLine(w.Elapsed);
}

Đầu ra:

00:00:00.4269033  // with try/catch
00:00:00.4260383  // without.

Tính bằng mili giây:

449
416

Mã mới:

for (int j = 0; j < 10; j++)
{
    Stopwatch w = new Stopwatch();
    double d = 0;
    w.Start();

    for (int i = 0; i < 10000000; i++)
    {
        try
        {
            d = Math.Sin(d);
        }

        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }

        finally
        {
            d = Math.Sin(d);
        }
    }

    w.Stop();
    Console.Write("   try/catch/finally: ");
    Console.WriteLine(w.ElapsedMilliseconds);
    w.Reset();
    d = 0;
    w.Start();

    for (int i = 0; i < 10000000; i++)
    {
        d = Math.Sin(d);
        d = Math.Sin(d);
    }

    w.Stop();
    Console.Write("No try/catch/finally: ");
    Console.WriteLine(w.ElapsedMilliseconds);
    Console.WriteLine();
}

Kết quả mới:

   try/catch/finally: 382
No try/catch/finally: 332

   try/catch/finally: 375
No try/catch/finally: 332

   try/catch/finally: 376
No try/catch/finally: 333

   try/catch/finally: 375
No try/catch/finally: 330

   try/catch/finally: 373
No try/catch/finally: 329

   try/catch/finally: 373
No try/catch/finally: 330

   try/catch/finally: 373
No try/catch/finally: 352

   try/catch/finally: 374
No try/catch/finally: 331

   try/catch/finally: 380
No try/catch/finally: 329

   try/catch/finally: 374
No try/catch/finally: 334

24
Bạn có thể thử chúng theo thứ tự ngược lại để chắc chắn rằng quá trình biên dịch JIT không có ảnh hưởng đến cái trước không?
JoshJordan

28
Các chương trình như thế này dường như không phải là ứng cử viên tốt để kiểm tra tác động của xử lý ngoại lệ, quá nhiều những gì sẽ xảy ra trong các khối {} bắt {} bình thường sẽ được tối ưu hóa. Tôi có thể ra ngoài ăn trưa vào ngày đó ...
LorenVS

30
Đây là một bản dựng gỡ lỗi. JIT không tối ưu hóa những thứ đó.
Ben M

7
Điều này không đúng chút nào, Hãy nghĩ về nó. Bao nhiêu lần bạn sử dụng thử bắt trong một vòng lặp? Hầu hết thời gian bạn sẽ sử dụng vòng lặp trong một lần thử.c
Athiwat Chunlakhan

9
Có thật không? "Làm thế nào để các khối thử / bắt ảnh hưởng đến hiệu suất khi ngoại lệ không bị ném?"
Ben M

105

Sau khi xem tất cả các số liệu thống kê với thử / bắt và không thử / bắt, sự tò mò buộc tôi phải nhìn phía sau để xem những gì được tạo ra cho cả hai trường hợp. Đây là mã:

C #:

private static void TestWithoutTryCatch(){
    Console.WriteLine("SIN(1) = {0} - No Try/Catch", Math.Sin(1)); 
}

MSIL:

.method private hidebysig static void  TestWithoutTryCatch() cil managed
{
  // Code size       32 (0x20)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldstr      "SIN(1) = {0} - No Try/Catch"
  IL_0006:  ldc.r8     1.
  IL_000f:  call       float64 [mscorlib]System.Math::Sin(float64)
  IL_0014:  box        [mscorlib]System.Double
  IL_0019:  call       void [mscorlib]System.Console::WriteLine(string,
                                                                object)
  IL_001e:  nop
  IL_001f:  ret
} // end of method Program::TestWithoutTryCatch

C #:

private static void TestWithTryCatch(){
    try{
        Console.WriteLine("SIN(1) = {0}", Math.Sin(1)); 
    }
    catch (Exception ex){
        Console.WriteLine(ex);
    }
}

MSIL:

.method private hidebysig static void  TestWithTryCatch() cil managed
{
  // Code size       49 (0x31)
  .maxstack  2
  .locals init ([0] class [mscorlib]System.Exception ex)
  IL_0000:  nop
  .try
  {
    IL_0001:  nop
    IL_0002:  ldstr      "SIN(1) = {0}"
    IL_0007:  ldc.r8     1.
    IL_0010:  call       float64 [mscorlib]System.Math::Sin(float64)
    IL_0015:  box        [mscorlib]System.Double
    IL_001a:  call       void [mscorlib]System.Console::WriteLine(string,
                                                                  object)
    IL_001f:  nop
    IL_0020:  nop
    IL_0021:  leave.s    IL_002f //JUMP IF NO EXCEPTION
  }  // end .try
  catch [mscorlib]System.Exception 
  {
    IL_0023:  stloc.0
    IL_0024:  nop
    IL_0025:  ldloc.0
    IL_0026:  call       void [mscorlib]System.Console::WriteLine(object)
    IL_002b:  nop
    IL_002c:  nop
    IL_002d:  leave.s    IL_002f
  }  // end handler
  IL_002f:  nop
  IL_0030:  ret
} // end of method Program::TestWithTryCatch

Tôi không phải là chuyên gia về IL nhưng chúng ta có thể thấy rằng một đối tượng ngoại lệ cục bộ được tạo trên dòng thứ tư .locals init ([0] class [mscorlib]System.Exception ex)sau đó mọi thứ khá giống với phương thức mà không cần thử / bắt cho đến dòng mười bảy IL_0021: leave.s IL_002f. Nếu một ngoại lệ xảy ra, điều khiển sẽ nhảy sang dòng IL_0025: ldloc.0nếu không chúng ta sẽ chuyển sang nhãn IL_002d: leave.s IL_002fvà trả về hàm.

Tôi có thể giả định rằng nếu không có ngoại lệ xảy ra sau đó nó là chi phí của việc tạo ra các biến địa phương để giữ ngoại lệ đối tượng duy nhất và một hướng dẫn nhảy.


33
Chà, IL bao gồm một khối thử / bắt trong cùng một ký hiệu như trong C #, vì vậy điều này không thực sự cho thấy mức độ cố gắng của một lần thử / bắt ở phía sau hậu trường! Chỉ là IL không thêm nhiều hơn nữa, không có nghĩa giống như nó không được thêm vào một cái gì đó trong mã lắp ráp được biên dịch. IL chỉ là một đại diện phổ biến của tất cả các ngôn ngữ .NET. Nó KHÔNG phải là mã máy!
kinh ngạc

64

Không. Nếu tối ưu hóa tầm thường một lần thử / cuối cùng chặn các loại trừ thực sự có tác động có thể đo lường được đối với chương trình của bạn, có lẽ bạn không nên sử dụng .NET ở nơi đầu tiên.


10
Đó là một điểm tuyệt vời - so với các mục khác trong danh sách của chúng tôi, mục này nên rất nhỏ. Chúng ta nên tin tưởng các tính năng ngôn ngữ cơ bản để hành xử chính xác và tối ưu hóa những gì chúng ta có thể kiểm soát (sql, chỉ mục, thuật toán).
Kobi

3
Hãy nghĩ về vòng lặp chặt chẽ bạn đời. Ví dụ vòng lặp nơi bạn đọc và khử nối tiếp các đối tượng từ luồng dữ liệu ổ cắm trong máy chủ trò chơi và bạn cố gắng siết chặt hết mức có thể. Vì vậy, MessagePack của bạn để tuần tự hóa đối tượng thay vì nhị phân, và sử dụng ArrayPool <byte> thay vì chỉ tạo các mảng byte, v.v ... Trong các trường hợp này, tác động của nhiều khối (có thể lồng nhau) hãy thử các khối bắt trong vòng lặp chặt chẽ. Một số tối ưu hóa sẽ bị bỏ qua bởi trình biên dịch, biến ngoại lệ sẽ chuyển sang Gen0 GC. Tất cả những gì tôi đang nói là có những kịch bản "Một số" trong đó mọi thứ đều có tác động.
tcwicks

35

Giải thích khá toàn diện về mô hình ngoại lệ .NET.

Tidbits hiệu suất của Rico Mariani: Chi phí ngoại lệ: Khi nào nên ném và khi nào không

Loại chi phí đầu tiên là chi phí tĩnh khi xử lý ngoại lệ trong mã của bạn. Các ngoại lệ được quản lý thực sự làm tương đối tốt ở đây, theo tôi, chi phí tĩnh có thể thấp hơn nhiều so với nói trong C ++. Tại sao lại thế này? Chà, chi phí tĩnh thực sự phát sinh ở hai loại: Thứ nhất, các trang web thực sự của thử / cuối cùng / bắt / ném trong đó có mã cho các cấu trúc đó. Thứ hai, trong mã không thay đổi, có chi phí lén lút liên quan đến việc theo dõi tất cả các đối tượng phải bị phá hủy trong trường hợp ném ngoại lệ. Có một số lượng đáng kể logic dọn dẹp phải có mặt và phần lén lút là mã thậm chí không có '

Dmitriy Zaslavskiy:

Theo ghi chú của Chris Brumme: Cũng có một chi phí liên quan đến thực tế là một số tối ưu hóa không được JIT thực hiện khi có mặt


1
Điều đáng nói về C ++ là một phần rất lớn của thư viện chuẩn sẽ đưa ra ngoại lệ. Không có gì tùy chọn về họ. Bạn phải thiết kế các đối tượng của mình với một số chính sách ngoại lệ và một khi bạn đã thực hiện điều đó thì sẽ không còn chi phí lén lút nữa.
David Thornley

Tuyên bố của Rico Mariani hoàn toàn sai đối với C ++ bản địa. "Chi phí tĩnh có thể thấp hơn nhiều so với nói trong C ++" - Điều này đơn giản là không đúng. Mặc dù, tôi không chắc thiết kế cơ chế ngoại lệ năm 2003 là gì khi bài báo được viết. C ++ thực sự không có chi phí nào khi các ngoại lệ không bị ném, bất kể bạn có bao nhiêu khối thử / bắt và chúng ở đâu.
BJovke

1
@BJovke C ++ "xử lý ngoại lệ chi phí bằng 0" chỉ có nghĩa là không có chi phí thời gian chạy khi các ngoại lệ không bị ném, nhưng vẫn có một chi phí kích thước mã lớn do tất cả các hàm hủy gọi mã dọn dẹp trên các ngoại lệ. Ngoài ra, mặc dù không có bất kỳ mã cụ thể ngoại lệ nào được tạo trên đường dẫn mã thông thường, chi phí vẫn không thực sự bằng 0, vì khả năng ngoại lệ vẫn hạn chế trình tối ưu hóa (ví dụ: công cụ cần thiết trong trường hợp ngoại lệ cần duy trì xung quanh một nơi nào đó -> các giá trị có thể bị loại bỏ ít tích cực hơn -> phân bổ đăng ký kém hiệu quả hơn)
Daniel

24

Cấu trúc là khác nhau trong ví dụ từ Bến M . Nó sẽ được mở rộng trên đầu bên trong forvòng lặp bên trong sẽ khiến nó không thể so sánh tốt giữa hai trường hợp.

Sau đây là chính xác hơn để so sánh trong đó toàn bộ mã cần kiểm tra (bao gồm khai báo biến) nằm trong khối Thử / Bắt:

        for (int j = 0; j < 10; j++)
        {
            Stopwatch w = new Stopwatch();
            w.Start();
            try { 
                double d1 = 0; 
                for (int i = 0; i < 10000000; i++) { 
                    d1 = Math.Sin(d1);
                    d1 = Math.Sin(d1); 
                } 
            }
            catch (Exception ex) {
                Console.WriteLine(ex.ToString()); 
            }
            finally { 
                //d1 = Math.Sin(d1); 
            }
            w.Stop(); 
            Console.Write("   try/catch/finally: "); 
            Console.WriteLine(w.ElapsedMilliseconds); 
            w.Reset(); 
            w.Start(); 
            double d2 = 0; 
            for (int i = 0; i < 10000000; i++) { 
                d2 = Math.Sin(d2);
                d2 = Math.Sin(d2); 
            } 
            w.Stop(); 
            Console.Write("No try/catch/finally: "); 
            Console.WriteLine(w.ElapsedMilliseconds); 
            Console.WriteLine();
        }

Khi tôi chạy mã kiểm tra gốc từ Ben M , tôi nhận thấy sự khác biệt cả về cấu hình Debug và Releas.

Phiên bản này, tôi nhận thấy sự khác biệt trong phiên bản gỡ lỗi (thực tế nhiều hơn phiên bản khác), nhưng nó không có gì khác biệt trong phiên bản Phát hành.

Conclution :
Dựa trên những thử nghiệm, tôi nghĩ chúng ta có thể nói rằng try / catch không có một tác động nhỏ về hiệu suất.

EDIT:
Tôi đã cố gắng tăng giá trị vòng lặp từ 10000000 lên 1000000000 và chạy lại trong Bản phát hành để có một số khác biệt trong bản phát hành và kết quả là:

   try/catch/finally: 509
No try/catch/finally: 486

   try/catch/finally: 479
No try/catch/finally: 511

   try/catch/finally: 475
No try/catch/finally: 477

   try/catch/finally: 477
No try/catch/finally: 475

   try/catch/finally: 475
No try/catch/finally: 476

   try/catch/finally: 477
No try/catch/finally: 474

   try/catch/finally: 475
No try/catch/finally: 475

   try/catch/finally: 476
No try/catch/finally: 476

   try/catch/finally: 475
No try/catch/finally: 476

   try/catch/finally: 475
No try/catch/finally: 474

Bạn thấy rằng kết quả là không quan trọng. Trong một số trường hợp, phiên bản sử dụng Thử / Bắt thực sự nhanh hơn!


1
Tôi cũng nhận thấy điều này, đôi khi nó nhanh hơn với thử / bắt. Tôi đã nhận xét về câu trả lời của Ben. Tuy nhiên, không giống như 24 cử tri, tôi không thích loại điểm chuẩn này, tôi không nghĩ đó là một dấu hiệu tốt. Mã này nhanh hơn trong trường hợp này, nhưng nó sẽ luôn luôn như vậy?
Kobi

5
Điều này không chứng minh rằng máy của bạn đã thực hiện một loạt các nhiệm vụ khác cùng một lúc? Thời gian trôi qua không bao giờ là một biện pháp tốt, bạn cần sử dụng một trình lược tả ghi lại thời gian của bộ xử lý, không phải là thời gian trôi qua.
Colin Desmond

2
@Kobi: Tôi đồng ý rằng đây không phải là cách tốt nhất để đánh giá nếu bạn định xuất bản nó như một bằng chứng cho thấy chương trình của bạn chạy nhanh hơn phương pháp khác hoặc một cái gì đó, nhưng có thể cung cấp cho bạn như một nhà phát triển chỉ ra một phương pháp hoạt động tốt hơn phương pháp khác . Trong trường hợp này, tôi nghĩ rằng chúng ta có thể nói rằng sự khác biệt (ít nhất là đối với cấu hình Phát hành) là không thể chấp nhận được.
kinh ngạc

1
Bạn không có thời gian try/catchở đây. Bạn đang định thời gian 12 lần thử / bắt phần quan trọng đối với các vòng 10M. Tiếng ồn của vòng lặp sẽ xóa bỏ mọi ảnh hưởng của thử / bắt. thay vào đó, nếu bạn đặt thử / bắt trong vòng lặp chặt chẽ và so sánh với / không, bạn sẽ phải trả giá bằng thử / bắt. (không còn nghi ngờ gì nữa, việc mã hóa như vậy nói chung không phải là thông lệ tốt, nhưng nếu bạn muốn vượt qua thời gian của công trình, đó là cách bạn thực hiện nó). Ngày nay, BenchmarkDotNet là công cụ hỗ trợ thời gian thực hiện đáng tin cậy.
Abel

15

Tôi đã kiểm tra tác động thực tế của một try..catchvòng lặp chặt chẽ và bản thân nó quá nhỏ để trở thành mối quan tâm về hiệu suất trong mọi tình huống thông thường.

Nếu vòng lặp thực hiện rất ít công việc (trong thử nghiệm của tôi, tôi đã làm x++), bạn có thể đo lường tác động của việc xử lý ngoại lệ. Vòng lặp với xử lý ngoại lệ mất khoảng mười lần để chạy.

Nếu vòng lặp thực hiện một số công việc thực tế (trong thử nghiệm của tôi, tôi đã gọi phương thức Int32.Pude), việc xử lý ngoại lệ có quá ít tác động để có thể đo lường được. Tôi có một sự khác biệt lớn hơn nhiều bằng cách hoán đổi thứ tự các vòng lặp ...


11

thử các khối bắt có tác động không đáng kể đến hiệu suất nhưng ngoại lệ Ném có thể khá lớn, đây có thể là đồng nghiệp của bạn đã nhầm lẫn.


8

Thử / bắt HAS tác động đến hiệu suất.

Nhưng nó không phải là một tác động lớn. độ phức tạp thử / bắt thường là O (1), giống như một phép gán đơn giản, ngoại trừ khi chúng được đặt trong một vòng lặp. Vì vậy, bạn phải sử dụng chúng một cách khôn ngoan.

Dưới đây là một tài liệu tham khảo về hiệu suất thử / bắt (không giải thích sự phức tạp của nó, nhưng nó được ngụ ý). Hãy nhìn vào Exceptions Ít Ném phần


3
Độ phức tạp là O (1) nó không có nghĩa quá nhiều. Ví dụ: nếu bạn trang bị một phần mã được gọi là rất thường xuyên với tính năng thử bắt (hoặc bạn đề cập đến một vòng lặp), thì các O (1) có thể thêm vào một số có thể đo được cuối cùng.
Csaba Toth

6

Về lý thuyết, khối try / Catch sẽ không ảnh hưởng đến hành vi mã trừ khi có ngoại lệ thực sự xảy ra. Tuy nhiên, có một số trường hợp hiếm hoi, trong đó sự tồn tại của khối thử / bắt có thể có ảnh hưởng lớn và một số trường hợp không phổ biến nhưng hầu như không bị che khuất trong đó hiệu ứng có thể thấy rõ. Lý do cho điều này là mã đã cho như:

Action q;
double thing1()
  { double total; for (int i=0; i<1000000; i++) total+=1.0/i; return total;}
double thing2()
  { q=null; return 1.0;}
...
x=thing1();     // statement1
x=thing2(x);    // statement2
doSomething(x); // statement3

trình biên dịch có thể tối ưu hóa statement1 dựa trên thực tế là statement2 được đảm bảo thực thi trước statement3. Nếu trình biên dịch có thể nhận ra rằng thing1 không có tác dụng phụ và thing2 không thực sự sử dụng x, thì nó hoàn toàn có thể bỏ qua điều1. Nếu [như trong trường hợp này] điều1 là đắt tiền, đó có thể là một tối ưu hóa lớn, mặc dù các trường hợp điều1 đắt tiền cũng là những trình biên dịch sẽ ít có khả năng tối ưu hóa nhất. Giả sử mã đã được thay đổi:

x=thing1();      // statement1
try
{ x=thing2(x); } // statement2
catch { q(); }
doSomething(x);  // statement3

Bây giờ tồn tại một chuỗi các sự kiện trong đó statement3 có thể thực thi mà không có statement2 đã thực thi. Ngay cả khi không có gì trong mã thing2có thể đưa ra một ngoại lệ, thì có thể là một luồng khác có thể sử dụng một Interlocked.CompareExchangethông báo qđã bị xóa và đặt nó thành Thread.ResetAbort, sau đó thực hiện một Thread.Abort()câu lệnh trước khi ghi giá trị của nó x. Sau đó, catchlệnh thực thi Thread.ResetAbort()[thông qua ủy nhiệm q], cho phép thực thi tiếp tục với statement3. Một chuỗi các sự kiện như vậy tất nhiên sẽ không thể thực hiện được, nhưng một trình biên dịch được yêu cầu để tạo mã hoạt động theo đặc tả ngay cả khi các sự kiện không thể xảy ra như vậy xảy ra.

Nhìn chung, trình biên dịch có nhiều khả năng nhận thấy các cơ hội để loại bỏ các đoạn mã đơn giản hơn các mã phức tạp, và do đó, rất hiếm khi một lần thử / bắt có thể ảnh hưởng đến hiệu năng nhiều nếu không bao giờ có ngoại lệ. Tuy nhiên, có một số tình huống trong đó sự tồn tại của khối thử / bắt có thể ngăn chặn tối ưu hóa - nhưng đối với thử / bắt - sẽ cho phép mã chạy nhanh hơn.


5

Mặc dù " Phòng ngừa tốt hơn xử lý ", trong viễn cảnh về hiệu suất và hiệu quả, chúng tôi có thể chọn thử bắt trước thay đổi trước. Hãy xem xét mã dưới đây:

Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int i = 1; i < int.MaxValue; i++)
{
    if (i != 0)
    {
        int k = 10 / i;
    }
}
stopwatch.Stop();
Console.WriteLine($"With Checking: {stopwatch.ElapsedMilliseconds}");
stopwatch.Reset();
stopwatch.Start();
for (int i = 1; i < int.MaxValue; i++)
{
    try
    {
        int k = 10 / i;
    }
    catch (Exception)
    {

    }
}
stopwatch.Stop();
Console.WriteLine($"With Exception: {stopwatch.ElapsedMilliseconds}");

Đây là kết quả:

With Checking: 20367
With Exception: 13998

4

Xem thảo luận về triển khai thử / bắt để biết thảo luận về cách các khối thử / bắt hoạt động và cách một số triển khai có chi phí cao và một số có chi phí không, khi không có ngoại lệ xảy ra. Cụ thể, tôi nghĩ rằng việc triển khai Windows 32 bit có chi phí hoạt động cao và việc triển khai 64 bit thì không.


Những gì tôi mô tả là hai cách tiếp cận khác nhau để thực hiện các ngoại lệ. Các cách tiếp cận áp dụng như nhau cho C ++ và C #, cũng như mã được quản lý / không được quản lý. Những cái mà MS đã chọn cho C # của họ tôi không biết chính xác, nhưng kiến ​​trúc xử lý ngoại lệ của các ứng dụng cấp máy do MS cung cấp sử dụng sơ đồ nhanh hơn. Tôi sẽ hơi ngạc nhiên nếu việc triển khai C # cho 64 bit không sử dụng nó.
Ira Baxter
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.