簡體   English   中英

沒有捕獲Python 2.7自定義異常

[英]Python 2.7 custom exception is not being caught

我正在使用自定義超時異常來解決iter(subprocess.Popen.stdout.readline,'')阻塞的問題,因為沒有更多的輸出要讀取,但是沒有正確捕獲異常。 這是一個既有主流程又有獨立流程(由multiprocessing.Process實現)的代碼,在這兩者中都可能發生超時。 相關部分是:

class Timeout(Exception):
    def __init__(self, message):
        self.message = message

def handle_timeout(signal, frame):
    raise Timeout("Timed out")

在主進程中可以很好地捕獲此自定義異常,但是在子進程中,無論何時引發超時,即使使用(我相信)適當的標准語法,也永遠不會捕獲該異常:

from subprocess import Popen, PIPE
subProc = Popen(('tail', '-f', fileName), stdout=PIPE, stderr=PIPE, shell=False, close_fds=True)
lines = iter(subProc.stdout.readline,'')
for line in lines:
    try:
        process_line(line)
    except Timeout as time_out:
        print(time_out.message)
        subProc.terminate()
        break

我沒有輸出超時消息並終止subProc,而是得到以下輸出:

Traceback (most recent call last):
  File "/home/username/anaconda2/envs/Py2.7/lib/python2.7/multiprocessing/process.py", line 267, in _bootstrap
    self.run()
  File "reader.py", line 50, in run
    for line in lines:
  File "reader.py", line 13, in handle_timeout
    raise Timeout("Timed out")
Timeout

handle_timeout自超時以來似乎工作正常,但是異常處理被忽略或跳過。 我在語法方面做錯了嗎,還是需要在子進程中定義一個單獨的自定義異常?

編輯:

之前的第二個代碼塊不完整。 這是當前存在的情況(包括chepner對iter(stdout.readline,'')不相關的建議):

from subprocess import Popen, PIPE
signal.signal(signal.SIGALRM, handle_timeout)
subProc = Popen(('tail', '-f', fileName), stdout=PIPE, stderr=PIPE, shell=False, close_fds=True)
for line in subProc.stdout:
    signal.alarm(CHILD_TIMEOUT)
    try:
        process_line(line)
    except Timeout as time_out:
        print(time_out.message)
        subProc.terminate()
        break

在父進程(超時異常完全按需工作)中,格式為:

# signal masking as in last block
while True:
    try:
        signal.alarm(MASTER_TIMEOUT) # different from CHILD_TIMEOUT
        other_processing()
    except Timeout:
        shutDown(children) # method to shut down child processes
        break

解決了:

我找到了解決方案。

subProc = Popen(('tail', '-f', fileName), stdout=PIPE, stderr=PIPE, shell=False, close_fds=True)
while not exit.is_set(): # exit is defined by multiprocessing.Event()
    signal.alarm(3)
    try:
        for line in subProc.stdout:
            process_line(line)
    except Timeout:
        print("Process timed out while waiting for log output")
        subProc.terminate()
        exit.set()

現在,當警報響起時,將觸發超時異常並按原應的方式捕獲該異常,在觸發退出條件之前結束子進程,然后子進程將正常關閉。

您實際上無法以處理代碼的方式在子進程內部捕獲錯誤。 您認為是使用事件捕獲來進行錯誤處理,或者實際上不是正在引發的子流程,執行代碼並管理響應。 由於您使用popopen手動控制子流程,因此需要手動處理其響應。

當您的子進程結束時,它應該返回0。如果它返回-1或1,則表明您已發生錯誤,需要從stderr讀取以捕獲錯誤。

EDIT1

我明白你的問題。 您編寫處理程序handle_timeout將抓住該錯誤並每次重新引發它。 您不能在多個地方處理異常。 因為它有兩個單獨的函數試圖同時處理同一錯誤。 這將始終產生沖突,並且第一個捕獲錯誤的沖突將導致您的主進程退出。 您可以在此處執行幾項不同的操作,但請允許我懇請您-不要無緣無故地吃掉錯誤。

修復1:刪除您的錯誤處理程序

def handle_timeout(signal, frame):
    raise Timeout("Timed out")

修復2:

try:
    process_line(line)
finally: 
    subProc.terminate()

以上將保證子進程的終止而不會產生錯誤。 另外,使用諸如handle_timeout處理程序之類的自定義句柄捕獲錯誤是一種幾乎專門用於在重新引發錯誤之前解構復雜運行或對象的技術。 它是最后一個解決方案,主要用於在發生特定錯誤后進行大量清理的情況。 如果要這樣做,請不要使用except塊。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM