Python - 让父线程处理子线程的异常

8 投票
4 回答
9034 浏览
提问于 2025-04-16 22:28

有没有办法让创建新线程的父线程能够捕捉到这个新线程的异常?下面是我想实现的一个非常简单的例子。当出现异常时,它应该停止计数,但我不知道怎么去捕捉这个异常。异常是线程安全的吗?我很想使用 Subprocess 模块,但我现在只能用 Python 2.3,不知道还有什么其他方法可以做到。也许可以使用 threading 模块?

import time
import thread

def test(): 
    try:
        test = thread.start_new_thread(watchdog, (5,))
        count(10)
    except:
        print('Stopped Counting')

def count(num):
    for i in range(num):
        print i
        time.sleep(1)

def watchdog(timeout):
    time.sleep(timeout)
    raise Exception('Ran out of time')

if __name__ == '__main__':
    test()

更新

我最初的代码有点误导。我其实想要的是这样的:

import time
import thread
import os

def test(): 
    try:
        test = thread.start_new_thread(watchdog, (5,))
        os.system('count_to_10.exe')
    except:
        print('Stopped Counting')

def watchdog(timeout):
    time.sleep(timeout)
    raise Exception('Ran out of time')

if __name__ == '__main__':
    test()

我想创建一个监视程序,如果程序因为某种原因卡住了,就终止 os.system 的调用。

4 个回答

2

如果你真正想做的是处理异常,那么我觉得你不应该使用子进程。因为父进程只能看到子进程返回的状态码和输出,只有在子进程发生严重错误时,异常才会在父进程中被“重新抛出”:http://docs.python.org/library/subprocess.html#exceptions

而且(如果你是想处理异常的话),我也不确定你需要使用线程。毕竟,我认为异常的主要目的就是让调用者可以处理它(在一个try块中),或者如果没有处理的话,可以提供有意义的回溯信息(调用顺序)。在一个线程中“抛出”异常而在另一个线程中“捕获”,这两种方式都不太适用。

如果你真正的目标是让一段逻辑“超时”另一段逻辑,那么我觉得让你的“监视者”成为一个独立的进程是有意义的——可以是一个“父进程”,监控“子进程”的输出和经过的时间,或者是一个“平行进程”,监控被监控进程的日志行和/或数据库更新(以及时间)。在这两种情况下,异常并不是特别相关。我建议你看看Alex Martelli对这个问题的回答:使用模块'subprocess'与超时

这个问题还有几个不错的答案,与你的问题相关: 在Python中捕获线程的异常到调用线程

2

卡在使用 Python 2.3

Python 2.3 现在差不多有十年了。你为什么还在用它呢?

可能是在用 threading 模块

其实你应该使用 threading 模块。

不过你可能对问题的理解有点偏差。你应该考虑创建一些类,重新思考一下你的问题解决方法。

另外,如果你在做一个监控程序,把它和你正在做的事情放在同一个进程里可能没什么意义。因为 time.sleep() 是一个系统调用,普通的 Python Exception 是无法取消它的。

3

为什么不试试这样做呢

def test(): 
    def exeption_cb():
        os._exit()
    test = thread.start_new_thread(watchdog, (5, exception_cb))
    os.system('count_to_10.exe')
    print('Stopped Counting')

def watchdog(timeout, callback):
    time.sleep(timeout)
    callback()

这样做会停止整个过程。你还可以选择在一个不同的线程中启动os.system,然后进行倒计时,最后再结束那个线程。可以这样做,

def system_call():
    os.system('count_to_10.exe')

system_thread = thread.start_new_thread(system_call)
time.sleep(timeout)
system_thread.kill()

撰写回答