python捕捉线程异常_python异步线程异常处理

我正在尝试在Python中实现超时功能.

它通过使用函数装饰器包装函数来工作,该函数装饰器将函数作为线程调用,还调用“看门狗”线程,该线程将在指定时间段后在函数线程中引发异常.

当前,它适用于不休眠的线程.在do_rand调用期间,我怀疑在time.sleep调用之后以及执行已超出try / except块之后,实际上正在调用“异步”异常,因为这将解释错误启动的线程中的Unhandled异常.此外,do_rand调用中的错误是在调用后7秒钟(time.sleep的持续时间)生成的.

我将如何“唤醒”线程(使用ctypes?)以使其响应异步异常?

或者可能是完全不同的方法?

码:

# Import System libraries

import ctypes

import random

import sys

import threading

import time

class TimeoutException(Exception):

pass

def terminate_thread(thread, exc_type = SystemExit):

"""Terminates a python thread from another thread.

:param thread: a threading.Thread instance

"""

if not thread.isAlive():

return

exc = ctypes.py_object(exc_type)

res = ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(thread.ident), exc)

if res == 0:

raise ValueError("nonexistent thread id")

elif res > 1:

# """if it returns a number greater than one, you're in trouble,

# and you should call it again with exc=NULL to revert the effect"""

ctypes.pythonapi.PyThreadState_SetAsyncExc(thread.ident, None)

raise SystemError("PyThreadState_SetAsyncExc failed")

class timeout_thread(threading.Thread):

def __init__(self, interval, target_thread):

super(timeout_thread, self).__init__()

self.interval = interval

self.target_thread = target_thread

self.done_event = threading.Event()

self.done_event.clear()

def run(self):

timeout = not self.done_event.wait(self.interval)

if timeout:

terminate_thread(self.target_thread, TimeoutException)

class timeout_wrapper(object):

def __init__(self, interval = 300):

self.interval = interval

def __call__(self, f):

def wrap_func(*args, **kwargs):

thread = threading.Thread(target = f, args = args, kwargs = kwargs)

thread.setDaemon(True)

timeout_ticker = timeout_thread(self.interval, thread)

timeout_ticker.setDaemon(True)

timeout_ticker.start()

thread.start()

thread.join()

timeout_ticker.done_event.set()

return wrap_func

@timeout_wrapper(2)

def print_guvnah():

try:

while True:

print "guvnah"

except TimeoutException:

print "blimey"

def print_hello():

try:

while True:

print "hello"

except TimeoutException:

print "Whoops, looks like I timed out"

def do_rand(*args):

try:

rand_num = 7 #random.randint(0, 10)

rand_pause = 7 #random.randint(0, 5)

print "Got rand: %d" % rand_num

print "Waiting for %d seconds" % rand_pause

time.sleep(rand_pause)

except TimeoutException:

print "Waited too long"

print_guvnah()

timeout_wrapper(3)(print_hello)()

timeout_wrapper(2)(do_rand)()

解决方法:

问题是time.sleep阻塞了.而且它真的很难阻挡,因此唯一可以中断它的是过程信号.但是带有它的代码真的很混乱,在某些情况下甚至信号也无法正常工作(例如,当您正在阻塞socket.recv()时,请参见:recv() is not interrupted by a signal in multithreaded environment).

因此,通常无法中断线程(而不杀死整个进程)(更不用说有人可以简单地从线程中重写信号处理).

但是在这种特殊情况下,您可以使用线程模块中的Event类来代替使用time.sleep:

线程1

from threading import Event

ev = Event()

ev.clear()

state = ev.wait(rand_pause) # this blocks until timeout or .set() call

线程2(确保它可以访问相同的ev实例)

ev.set() # this will unlock .wait above

请注意,状态将是事件的内部状态.因此,状态== True表示已使用.set()解锁,而状态== False则表示发生了超时.

在此处阅读有关事件的更多信息:

标签:multithreading,asynchronous,exception,ctypes,python