我有一组要并行执行的任务,但最后,我需要知道是否有任何线程抛出异常。 我不需要直接处理异常,我只需要知道其中一个线程是否因异常而失败,所以我可以干净地终止脚本
这是一个简单的例子:
#!/usr/bin/python
from time import sleep
from threading import Thread
def func(a):
for i in range(0,5):
print a
sleep(1)
def func_ex():
sleep(2)
raise Exception("Blah")
x = [Thread(target=func, args=("T1",)), Thread(target=func, args=("T2",)), Thread(target=func_ex, args=())]
print "Starting"
for t in x:
t.start()
print "Joining"
for t in x:
t.join()
print "End"
在“结束”之前,我想遍历线程,查看是否有任何失败,然后决定是否可以继续使用脚本,或者我是否需要在此时退出。
我不需要拦截异常或停止其他线程,我只需要知道最后是否有任何失败。
答案 0 :(得分:7)
当线程上的join()
调用返回时,线程的堆栈已被解除,并且有关异常的所有信息都已丢失。因此,遗憾的是,您需要提供自己的注册异常机制;讨论了一些技术here。
答案 1 :(得分:1)
对于不需要处理异常的情况,一种简单的技术是使用全局列表并向其附加相关信息。您的代码将变为:
#!/usr/bin/python
from time import sleep
from threading import Thread, current_thread #needed to get thread name or whatever identifying info you need
threadErrors = [] #global list
def func(a):
for i in range(0,5):
print a
sleep(1)
def func_ex():
global threadErrors #if you intend to change a global variable from within a different scope it has to be declared
try:
sleep(2)
raise Exception("Blah")
except Exception, e:
threadErrors.append([repr(e), current_thread.name]) #append a list of info
raise #re-raise the exception or use sys.exit(1) to let the thread die and free resources
x = [Thread(target=func, args=("T1",)), Thread(target=func, args=("T2",)), Thread(target=func_ex, args=())]
print "Starting"
for t in x:
t.start()
print "Joining"
for t in x:
t.join()
if len(threadErrors) > 0: #check if there are any errors
for e in threadErrors:
print(threadErrors[e][0]+' occurred in thread: '+threadErrors[e][1])
#do whatever with each error info
else:
#there are no errors so do normal clean-up stuff
#do clean-up that should happen in either case here
print "End"
注意:全局变量通常被视为技术不佳,但它们是线程之间通信的简单机制。你只需要记住,如果一个线程通过这个路由发送信息,那么另一个线程就必须寻找它。
答案 2 :(得分:1)
如果您要在测试中进行此操作,建议您使用pytest-reraise 有了它,您可以执行以下操作:
def test_assert(reraise):
def run():
with reraise:
assert False
reraise() # This will not raise anything yet
t = Thread(target=run)
t.start()
t.join()
reraise() # This will raise the assertion error