Python 主线程捕获子线程异常

作者: PengMeng | 来源:发表于2015-06-06 12:30 被阅读5691次

多线程异常

接上一篇Python手动中断(Ctrl-C)多线程程序,这一篇来探讨多线程程序中另一个问题:主线程捕获子线程异常。
博客原文

为什么会产生这个问题

先来看这个问题对应的代码是怎样的:

import time
from threading import Thread


class CountDown(Thread):
    def __init__(self):
        super(CountDown, self).__init__()

    def run(self):
        num = 100
        print('slave start')
        for i in range(5, -1, -1):
            print('Num: {0}'.format(num/i))
            time.sleep(1)
        print('slave end')


if __name__ == '__main__':
    print('main start')
    try:
        td = CountDown()
        td.start()
        td.join()
    except Exception as e:
        print(e)
    print('main end')

代码很直观,每秒打印一个值,当i==0时,除法会抛出ZeroDivisionError: integer division or modulo by zero异常。代码在2、3中表现基本一致,因此只讨论Python2的情况。
执行上述代码,得到下面的输出:

main start
slave start
Num: 20
Num: 25
Num: 33
Num: 50
Num: 100
Exception in thread Thread-1:
Traceback (most recent call last):
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 810, in __bootstrap_inner
    self.run()
  File "multithread.py", line 14, in run
    print('Num: {0}'.format(num/i))
ZeroDivisionError: integer division or modulo by zero

main end

可见,子线程产生了异常但并没有被主线程所捕获,因为主线程和子线程分别使用各自的栈,主线程并不能截获子线程调用过程中的异常。在子线程异常退出后,主线程执行了后续代码(此时主线程不知道子线程的退出状态)。

解决方案

将代码修改为:

import time
import sys
import traceback
from threading import Thread


class CountDown(Thread):
    def __init__(self):
        super(CountDown, self).__init__()
        self.exitcode = 0
        self.exception = None
        self.exc_traceback = ''

    def run(self):
        try:
            self._run()
        except Exception as e:
            self.exitcode = 1
            self.exception = e
            self.exc_traceback = ''.join(traceback.format_exception(*sys.exc_info()))

    def _run(self):
        num = 100
        print('slave start')
        for i in range(5, -1, -1):
            print('Num: {0}'.format(num/i))
            time.sleep(1)
        print('slave end')


if __name__ == '__main__':
    print('main start')
    td = CountDown()
    td.start()
    td.join()
    if td.exitcode != 0:
        print('Exception in ' + td.getName() + ' (catch by main)')
        print(td.exc_traceback)
    print('main end')

由于子线程运行结束后,其内存并没有被回收,因此可以继续使用该实例获得其成员变量。基于这一点,我们可以通过添加模拟线程退出信息的成员变量来记录子线程退出状态。可通过systraceback两个库实现这一点(完整Demo)。通过检查子线程exitcode,主线程可以知道其退出状态,然后做相应的处理。
代码输出:

main start
slave start
Num: 20
Num: 25
Num: 33
Num: 50
Num: 100
Exception in Thread-1 (catch by main)
Traceback (most recent call last):
  File "multithread.py", line 17, in run
    self._run()
  File "multithread.py", line 27, in _run
    print('Num: {0}'.format(num/i))
ZeroDivisionError: integer division or modulo by zero

main end

可以看出,该方法可以在主线程中获得子线程的异常信息,从而为debug提供了依据。除此之外,因为子线程抛出的异常大多为RuntimeError(其他异常应该在子线程内部处理),主线程检测到子线程异常退出后可以做一些相应的处理及恢复。

相关文章

  • Java多线程: 如何捕获多线程中的异常

    你处理过多线程中异常吗?如何捕获多线程中发生的异常?捕获子线程的异常与捕获当前线程的异常一样简单吗? 除了try ...

  • JAVA多线程

    1、主线程怎么捕获子线程的异常 因此,异常一定要在线程内部消化。也就是说主线程无法捕获子线程的异常; 2、现在有T...

  • 2019-12-20

    1、多线程中怎么捕获子线程中的异常?这个问题大家会经常遇到,子线程在执行过程中抛出了异常,但是主线程并没有捕获到。...

  • Python 主线程捕获子线程异常

    多线程异常 接上一篇Python手动中断(Ctrl-C)多线程程序,这一篇来探讨多线程程序中另一个问题:主线程捕获...

  • 多线程的异常和事务

    子线程中的异常在主线程中是不可以catch的在spring中主线程有事务,那么子线程中有事务么? 捕获异常 我们使...

  • Java 子线程异常捕获

    实现UncaughtExceptionHandler主线程可以轻松发现异常,子线程却不行。线程异常处理器的调用策略...

  • 调用线程不可捕捉异步线程的异常,如何处理?

    一 背景描述 Java的异常在线程之间不是共享的,在线程中抛出的异常是线程自己的异常,主线程并不能捕获到。也就是说...

  • java Integer.ParseInt()

    这个异常没有捕获,导致线程异常终止而不知道原因

  • Java线程<第四篇>:Hook线程以及捕获线程执行异常

    一、捕获线程执行异常 Java为我们提供了一个 UncaughtExceptionHandler 接口,当线程在运...

  • 多线程之线程属性

    线程属性 线程优先级 守护线程 线程组 处理未捕获异常的处理器 1. 线程优先级 在java中,每个线程都有一个...

网友评论

    本文标题:Python 主线程捕获子线程异常

    本文链接:https://www.haomeiwen.com/subject/awgdqttx.html