2016-01-22 19 views
15

Tôi viết một máy chủ xử lý các sự kiện và các ngoại lệ chưa nắm bắt trong khi xử lý sự kiện không được chấm dứt máy chủ.Vòng lặp vô tận mạnh mẽ cho máy chủ được viết bằng Python

Máy chủ là một quá trình python không phải luồng đơn.

Tôi muốn chấm dứt bằng các loại lỗi:

  • KeyboardInterrupt
  • MemoryError
  • ...

Danh mục xây dựng trong trường hợp ngoại lệ là dài: https://docs.python.org/2/library/exceptions.html

Tôi không muốn phát minh lại việc xử lý ngoại lệ này, vì tôi đoán nó đã được thực hiện al lần trước.

Làm cách nào để tiếp tục?

  1. Có một danh sách trắng: Một danh sách các trường hợp ngoại lệ mà là ok và xử lý sự kiện tiếp theo là lựa chọn đúng đắn
  2. Có một danh sách đen: Một danh sách các trường hợp ngoại lệ mà chỉ ra rằng chấm dứt máy chủ là quyền lựa chọn.

Gợi ý: Câu hỏi này không phải là chạy một trình nền ẩn trong nền. Nó không phải là về ngã ba đôi và không về chuyển hướng stdin/stdout :-)

Trả lời

2

Ngoại lệ cao nhất là BaseException. Có hai nhóm dưới rằng:

  • Exception có nguồn gốc
  • mọi thứ khác

Những điều như Stopiteration, ValueError, TypeError vv, là những ví dụ của Exception.

Những thứ như GeneratorExit, SystemExitKeyboardInterrupt không phải là hậu duệ của Execption.

Vì vậy, bước đầu tiên là bắt Exception và không phải BaseException sẽ cho phép bạn dễ dàng chấm dứt chương trình. Tôi cũng khuyên bạn nên bắt GeneratorExit là 1) nó sẽ không bao giờ thực sự được nhìn thấy trừ khi nó được nâng lên bằng tay; 2) bạn có thể đăng nhập và khởi động lại vòng lặp; và 3) nó được thiết kế để báo hiệu một máy phát điện đã thoát và có thể được dọn sạch, không phải là chương trình nên thoát.

Bước tiếp theo là ghi lại từng ngoại lệ với đủ chi tiết mà bạn có khả năng tìm ra điều gì đã xảy ra (khi sau này bạn gặp gỡ lỗi).

Cuối cùng, bạn phải quyết định cho chính mình mà, nếu có, của Exception trường hợp ngoại lệ có nguồn gốc bạn muốn chấm dứt vào lúc: Tôi sẽ đề nghị RuntimeErrorMemoryError, mặc dù bạn có thể để có được xung quanh những bằng cách đơn giản dừng lại và khởi động lại của bạn vòng lặp máy chủ.

Vì vậy, thực sự, tùy thuộc vào bạn.

Nếu có một số lỗi khác (như IOError khi cố gắng tải tệp cấu hình) đủ nghiêm trọng để thoát, thì mã chịu trách nhiệm tải tệp cấu hình phải đủ thông minh để bắt được IOError và tăng SystemExit thay thế.

Theo danh sách trắng/danh sách đen - hãy sử dụng danh sách đen, vì sẽ chỉ có một số ít, nếu có, Exception ngoại lệ dựa trên mà bạn cần thực sự chấm dứt máy chủ.

+1

Điều này cũng có thể giúp quyết định về việc quản lý phân biệt ngoại lệ được xây dựng trong: https://docs.python.org/3.5/library/exceptions.html#exception-hierarchy – Timur

4

tôi sẽ làm điều này trong một cách tương tự như bạn đang nghĩ đến việc sử dụng của bạn sẽ không vượt qua 'Gandalf xử lý ngoại lệ except Exception to catch all non-system-exiting exceptions trong khi tạo ra các trường hợp ngoại lệ được liệt kê đen set cần vượt qua và kết thúc sẽ được nâng cấp lại.

Sử dụng Gandalf handler sẽ đảm bảo GeneratorExit, SystemExitKeyboardInterrupt (tất cả các trường hợp ngoại lệ hệ thống thoát) vượt qua và chấm dứt chương trình nếu không có bộ xử lý khác có mặt cao hơn trong các cuộc gọi stack. Đây là nơi bạn có thể kiểm tra với type(e) rằng __class__ của ngoại lệ bị bắt e thực sự thuộc về bộ ngoại lệ được liệt kê đen và lại raise nó.

Như một cuộc biểu tình nhỏ:

import exceptions # Py2.x only 

# dictionary holding {exception_name: exception_class} 
excptDict = vars(exceptions) 

exceptionNames = ['MemoryError', 'OSError', 'SystemError'] # and others 

# set containing black-listed exceptions 
blackSet = {excptDict[exception] for exception in exceptionNames} 

Bây giờ blackSet = {OSError, SystemError, MemoryError} giữ lớp học của phi hệ thống thoát ngoại lệ chúng tôi muốn không xử lý.

Một try-except khối bây giờ có thể trông như thế này:

try: 
    # calls that raise exceptions: 
except Exception as e: 
    if type(e) in blackSet: raise e # re-raise 
    # else just handle it 

Một dụ mà bắt tất cả các trường hợp ngoại lệ sử dụng BaseException có thể giúp minh họa những gì tôi có ý nghĩa. (điều này được thực hiện cho mục đích trình diễn chỉ, để xem cách thức tăng này cuối cùng sẽ chấm dứt chương trình của bạn).Lưu ý: Tôi là không đề xuất bạn sử dụng BaseException; Tôi đang sử dụng nó để chứng minh gì ngoại lệ sẽ thực sự 'đi qua' và gây chấm dứt (tức là tất cả những gì BaseException đánh bắt):

for i, j in excptDict.iteritems(): 
    if i.startswith('__'): continue # __doc__ and other dunders 
    try: 
     try: 
      raise j 
     except Exception as ex: 
      # print "Handler 'Exception' caught " + str(i) 
      if type(ex) in blackSet: 
       raise ex   
    except BaseException: 
     print "Handler 'BaseException' caught " + str(i) 

# prints exceptions that would cause the system to exit  
Handler 'BaseException' caught GeneratorExit 
Handler 'BaseException' caught OSError 
Handler 'BaseException' caught SystemExit 
Handler 'BaseException' caught SystemError 
Handler 'BaseException' caught KeyboardInterrupt 
Handler 'BaseException' caught MemoryError 
Handler 'BaseException' caught BaseException 

Cuối cùng, để làm cho Python này 2/3 thuyết bất khả tri , bạn có thể tryimport exceptions và nếu điều đó không thành công (trong Python 3), hãy quay lại nhập builtins chứa tất cả Exceptions; chúng tôi tìm kiếm từ điển theo tên nên nó làm cho không có sự khác biệt:

try: 
    import exceptions 
    excDict = vars(exceptions) 
except ImportError: 
    import builtins 
    excDict = vars(builtins) 

Tôi không biết nếu có một cách thông minh hơn để thực sự làm được điều này, một giải pháp khác có thể là thay vì có một try-except với một signle except, có 2 các trình xử lý, một cho các trường hợp ngoại lệ được liệt kê đen và trường hợp khác cho trường hợp chung:

try: 
    # calls that raise exceptions: 
except tuple(blackSet) as be: # Must go first, of course. 
    raise be 
except Exception as e: 
    # handle the rest 
Các vấn đề liên quan