如何捕获线程中发生的异常?

问题描述 投票:1回答:1

Context:我有一个类中的所有方法的列表,这些方法都在线程中启动。预计其中一些方法会引发异常,并且这些异常必须在主程序中处理(=不在方法本身中)。

问题:未捕获到异常,并且解释(成功/失败)是错误的,因为所有线程都“成功”。

我认为本来可以的工作:一个try / except,其中的线程实际上是start()

[请注意在回溯中,两个答案都是(...) was successful,就好像try仅处理启动线程(.start())的事实,而不处理线程本身正在发生的事情。

import threading

class Checks:

    @staticmethod
    def isok():
        print("OK")

    @staticmethod
    def isko():
        raise Exception("KO")

# db will keep a map of method names in Check with the actual (executable) method
db = {}

# getting all the methods from Checks, without the built_in ones
for check in [k for k in dir(Checks) if not k.startswith('_')]:
    # create a thread for the method
    db[check] = threading.Thread(target=getattr(Checks, check))
    try:
        # start the thread
        db[check].start()
    except Exception:
        print(f"{check} raised an exception")
    else:
        print(f"{check} was successful")

# wait for all the threads to be finished
for thread in db.keys():
    db[thread].join()

# all the threads are finished at that point
print("all threads are done")

输出:

Exception in thread Thread-1:
Traceback (most recent call last):
  File "C:\Users\yop\AppData\Local\Programs\Python\Python37-32\lib\threading.py", line 926, in _bootstrap_inner
    self.run()
  File "C:\Users\yop\AppData\Local\Programs\Python\Python37-32\lib\threading.py", line 870, in run
    self._target(*self._args, **self._kwargs)
  File "C:/Users/yop/.PyCharm2019.2/config/scratches/scratch_6.py", line 11, in isko
    raise Exception("KO")
Exception: KO

isko was successful
OK
isok was successful
all threads are done

(由于线程的原因,回溯将与程序的实际输出混合,但是顺序始终相同)

编辑:关注评论,我想再次强调一下,异常将在方法中发生,但必须在主程序中捕获(=在方法本身中未处理)。

在非线程方法中,这很容易:与上面类似的代码中的try / exception子句会在它们冒泡时捕获它们。

python python-3.x multithreading
1个回答
0
投票

错误发生在另一个线程中,您正在尝试处理主线程中的错误,但是对于主线程,该错误不存在,因此您只需要在发生错误的线程中捕获错误。

如果确定需要在主线程中捕获它,则应使用子线程中的错误处理,然后通过使用一些同步化原语(例如Queue)将其发送到主线程。

import threading
from queue import Queue

class Checks:
    @staticmethod
    def isok(q):
        print("OK")

    @staticmethod
    def isko(q):  
        try:
            raise Exception("KO")  # add error handling to the child thread
        except:
            q.put("ERROR_" + threading.current_thread().getName())

# db will keep a map of method names in Check with the actual (executable) method
db = {}

# create Queue for synchronization
q = Queue()

# getting all the methods from Checks, without the built_in ones
for check in [k for k in dir(Checks) if not k.startswith('_')]:
    # create a thread for the method
    db[check] = threading.Thread(target=getattr(Checks, check), args=(q,))
    db[check].start()

# wait for all the threads to be finished with error or not
for thread in db.keys():
    db[thread].join()

# check if some threads were with errors and print the errors
if not q.empty():
    while True:   
        x = q.get()
        print(x)
        if q.empty():
            break

# all the threads are finished at that point
print("all threads are done")
© www.soinside.com 2019 - 2024. All rights reserved.