【问题标题】:How to catch an exception which occured in a thread? [duplicate]如何捕获线程中发生的异常? [复制]
【发布时间】:2020-03-04 21:41:45
【问题描述】:

注意:我的问题在副本中有one exact answer(另请参阅下面的修改代码的答案)。谢谢@quamrana 的指点

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

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

我认为可行的方法:一个try/except,其中的线程实际上是start()

请注意,在 Traceback 中,两个答案都是 (...) 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

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

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

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

【问题讨论】:

  • 您可以使用logging 记录线程中的错误。
  • 或者你可以使用一些线程安全的数据结构来存储错误,然后在main中读取。
  • @JayVasant:由于方法的性质,正如我在问题中提到的,必须在主程序中捕获异常(它们发生的事实会在实际情况下触发进一步的操作)
  • 追溯每一个功能
  • @SaisivaA:我不明白该怎么做? (你也许可以把它放在答案中?)

标签: python python-3.x multithreading


【解决方案1】:

an answer to another question 中给出了我的问题的确切答案(我将我的问题标记为重复,但它确实是在我的上下文中完美的特定答案)。

我的问题中的代码已修改以说明解决方案:

import concurrent.futures

class Checks:

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

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

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

with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor:
    for check in [k for k in dir(Checks) if not k.startswith('_')]:
        db[check] = executor.submit(getattr(Checks, check))
    for future in concurrent.futures.as_completed([db[k] for k in db.keys()]):
        if future.exception():
            print(f"{str(future.exception())} was raised (I do not know where, somewhere)")
        else:
            print("success (again, I do not know where, exactly)")

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

我不知道如何获取引发异常的未来的名称(我会问a new question

【讨论】:

    【解决方案2】:

    创建一个队列来捕获异常。

    errors = queue.Queue()

    def threaded_func():
      try:
        # perform some task
      except:
        errors.put(  
          # push into queue as required
        )
    
    def main():
      while True and threads_running:
       if errors.__len__():
         error_in_main = errors.pop()
         # handle the error as required.
    

    使用这种方式,您几乎可以立即捕获主线程中的错误并根据需要执行操作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-26
      • 2010-12-27
      相关资源
      最近更新 更多