Sử dụng các trường hợp ngoại lệ bắt gặp, cải thiện khả năng đọc, tốt hay xấu?


9

Trong phần Khi nào nên sử dụng ngoại lệ trong Lập trình viên thực dụng , cuốn sách viết rằng thay vì:

retcode = OK;
     if (socket.read(name) != OK) {
      retcode = BAD_READ;
    }
     else {
      processName(name);
       if (socket.read(address) != OK) {
        retcode = BAD_READ;
      }
       else {
        processAddress(address);
         if (socket.read(telNo) != OK) {
          retcode = BAD_READ;
        }
         else {
          //  etc, etc...
        }
      }
    }
     return retcode;

, họ thích:

 retcode = OK;
     try {
      socket.read(name);
      process(name);
      socket.read(address);
      processAddress(address);
      socket.read(telNo);
      //  etc, etc...
    }
     catch (IOException e) {
      retcode = BAD_READ;
      Logger.log( "Error reading individual: " + e.getMessage());
    }
     return retcode;

đơn giản vì nó trông gọn gàng hơn. Tôi là tất cả cho mã gọn gàng hơn, tuy nhiên không cần thiết phải bắt Ngoại lệ một nút cổ chai hiệu năng?

Tôi có thể hiểu rằng chúng ta nên từ bỏ tối ưu hóa cực nhỏ cho mã gọn gàng hơn (ít nhất 99% số lần), tuy nhiên từ những gì tôi biết, việc bắt ngoại lệ thuộc về lớp mã có độ trễ đáng chú ý trong thời gian chạy. Do đó tôi đã tự hỏi những gì biện minh rằng đoạn mã thứ hai được ưa thích hơn mã đầu tiên?

Hay đúng hơn, bạn thích mã nào?


di chuyển từ Đánh giá mã vì câu hỏi thực hành tốt nhất không phải là câu hỏi đánh giá mã
Winston Ewert

1
IMO, nếu bạn đang mong đợi có thể đọc các valuse đó từ ổ cắm, thì IOEx ngoại lệ.
Steven Evers


Bạn đã đo chưa?

@ ThorbjørnRavnAndersen tất nhiên tôi đã đọc cuốn sách và không có "trường hợp thử nghiệm" thực sự để đo .. nhưng nếu chúng tôi đo nó trong một mã bị
tước

Câu trả lời:


18

Các ngoại lệ thường chỉ chậm hơn nếu chúng thực sự bị ném. Thông thường, các trường hợp ngoại lệ trong các tình huống như thế này rất hiếm vì vậy nó không phải là điều bạn nên lo lắng. Bạn chỉ nên thực sự lo lắng về hiệu suất của các ngoại lệ nếu chúng xảy ra mọi lúc và do đó là một yếu tố quan trọng.

Mã thứ hai là tốt hơn bởi vì nó dễ dàng hơn để theo logic. Việc xử lý lỗi được bản địa hóa độc đáo. Sự phản đối duy nhất là nếu bạn đang sử dụng ngoại lệ, thì hãy sử dụng ngoại lệ. Đừng bắt ngoại lệ và sau đó trả lại mã lỗi.


4
Đồng ý, tôi ghét nhìn thấy mã lỗi trong một ngôn ngữ có ngoại lệ. Hầu hết thời gian bạn nên bắt, đăng nhập, suy nghĩ lại mà không phá vỡ ngăn xếp cuộc gọi. Và hầu hết thời gian, không có vấn đề gì nếu trường hợp "ngoại lệ" chậm hơn. Ứng dụng có vấn đề, hãy dành thời gian để xử lý nó đúng cách. Miễn là ngoại lệ là ngoại lệ và không phải là một phần của hoạt động bình thường hoặc đường dẫn hạnh phúc của ứng dụng, đó thường không phải là mùi mã.
CaffGeek

Btw Tôi đã tự hỏi làm thế nào để chúng tôi biện minh cho EOFException mà DataStreams sử dụng để phát hiện một dòng kết thúc (cuối dòng không phải là ngoại lệ) như được minh họa trong docs.oracle.com/javase/tutorial/essential/io/datastreams.html ?
Pacerier

@Pacerier, nó có thể là đặc biệt. Hết đầu vào trong dòng có thể chỉ ra dữ liệu xấu hoặc có gì đó không ổn. Tôi nghi ngờ mục đích sử dụng là phân tích một số trường trong một dòng.
Winston Ewert

@Downvoter, nếu bạn có vấn đề với câu trả lời, vui lòng giải thích!
Winston Ewert

5

Vâng, như họ cũng nói, các trường hợp ngoại lệ nên xử lý các trường hợp ngoại lệ , và vì đây là trường hợp ngoại lệ (nghĩa là có một vài điều xảy ra ở giữa và xa) tôi nói rằng điều này cũng áp dụng ở đây.

Ngoài ra, tôi muốn tư vấn cho chống lại điều vi tối ưu hóa như thế này. Tập trung nhiều hơn vào tính dễ đọc của mã , vì bạn sẽ dành nhiều thời gian hơn để đọc mã hơn là viết mã mới.

Để thực sự chắc chắn rằng đây là một nút cổ chai hiệu năng, hãy thực hiện một số lược tả và phân tích và tập trung vào các nhiệm vụ quan trọng hơn dựa trên phân tích đó.


5

Tôi có thể hiểu rằng chúng ta nên từ bỏ tối ưu hóa cực nhỏ cho mã gọn gàng hơn (ít nhất 99% số lần), tuy nhiên từ những gì tôi biết, việc bắt ngoại lệ thuộc về lớp mã có độ trễ đáng chú ý trong thời gian chạy.

Bạn biết điều đó từ đâu? Làm thế nào để bạn xác định "sự chậm trễ đáng chú ý"?

Đây chính xác là loại huyền thoại hiệu suất mơ hồ (và hoàn toàn sai) dẫn đến tối ưu hóa sớm vô dụng.

Ném và bắt một ngoại lệ có thể chậm so với việc thêm hai số, nhưng nó hoàn toàn không đáng kể so với việc đọc dữ liệu từ ổ cắm. Bạn có thể có thể ném và bắt hàng ngàn ngoại lệ trong cùng một lúc bạn đọc một gói mạng. Và chúng ta không nói về hàng ngàn trường hợp ngoại lệ ở đây, chỉ một trường hợp duy nhất.


Tôi đến từ .NET vì đã bỏ qua kiến ​​thức về Java, nhưng cá nhân tôi đã gặp phải trường hợp ngoại lệ trong .NET gây ra sự chậm trễ điên rồ (cường độ giây) đã được khắc phục bằng cách xóa "mã ngoại lệ bắt" ..
Pacerier

@Pacerier, nghiêm túc chứ? độ lớn của giây? Tôi đoán có lẽ nó đã bắt được rất nhiều ngoại lệ? Sau đó tôi có thể thấy điều đó.
Winston Ewert

3
@Pacerier: Nếu các trường hợp ngoại lệ gây ra sự chậm trễ điên rồ, rõ ràng những gì gây ra chúng không phải là ngoại lệ, và do đó nên được xử lý theo những cách khác. Không có hệ thống nào phải mất vài giây để xử lý một ngoại lệ và tôi nghĩ rằng Microsoft đủ khả năng để tránh điều đó.
David Thornley

5

Tôi đồng ý với câu trả lời mà bạn đã nhận được rằng đây là trường hợp đặc biệt, vì vậy sử dụng xử lý ngoại lệ một cách hợp lý.

Giải quyết vấn đề hiệu suất của bạn trực tiếp hơn, tôi nghĩ bạn cần giữ ý thức về quy mô về mọi thứ. Ném / bắt một ngoại lệ trong những trường hợp này có thể sẽ nhận được một thứ tự của một phần triệu giây. Khi kiểm soát dòng chảy, điều đó chậm - chậm hơn nhiều lần so với ifbáo cáo bình thường , không có câu hỏi về điều đó.

Đồng thời, hãy nhớ rằng những gì bạn đang làm ở đây là đọc dữ liệu từ mạng. Với tốc độ 10 megabit / giây (chậm đối với mạng cục bộ, nhưng khá nhanh khi kết nối Internet đi), đó là thứ tự giống như thời gian để đọc một byte thông tin.

Tất nhiên, chi phí đó chỉ phát sinh khi bạn thực sự ném ngoại lệ - khi nó không bị ném, thường sẽ có rất ít hoặc không có chi phí nào cả (ít nhất là từ những gì tôi đã thấy, chi phí quan trọng nhất không phải từ ngoại lệ tự xử lý, như từ việc thêm nhiều luồng điều khiển tiềm năng, làm cho mã khó hơn cho trình biên dịch để tối ưu hóa khá tốt).

Trong trường hợp này, khi một ngoại lệ được ném, dữ liệu ghi của bạn vào nhật ký. Do tính chất của việc ghi nhật ký, rất có thể bạn sẽ hoàn thành công việc đó ngay khi bạn viết nó (để đảm bảo nó không bị mất). Ghi vào đĩa là (một lần nữa) hoạt động khá chậm - bạn cần một ổ SSD cấp doanh nghiệp khá nhanh để thậm chí có thể vào trong phạm vi hàng chục ngàn IOP / giây. Một đĩa được sử dụng để ghi nhật ký có thể dễ dàng bị giới hạn ở mức hàng trăm IOP / giây.

Điểm mấu chốt: có những trường hợp xử lý ngoại lệ có thể là đáng kể, nhưng điều này gần như chắc chắn không phải là một trong số đó.

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.