Context:我有一个类中的所有方法的列表,这些方法都在线程中启动。预计其中一些方法会引发异常,并且这些异常必须在主程序中处理(=不在方法本身中)。
问题:未捕获到异常,并且解释(成功/失败)是错误的,因为所有线程都“成功”。
我认为本来可以的工作:一个try
/ except
,其中的线程实际上是start()
。
[请注意在回溯中,两个答案都是(...) 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
(由于线程的原因,回溯将与程序的实际输出混合,但是顺序始终相同)
编辑:关注评论,我想再次强调一下,异常将在方法中发生,但必须在主程序中捕获(=在方法本身中未处理)。
在非线程方法中,这很容易:与上面类似的代码中的try
/ exception
子句会在它们冒泡时捕获它们。
错误发生在另一个线程中,您正在尝试处理主线程中的错误,但是对于主线程,该错误不存在,因此您只需要在发生错误的线程中捕获错误。
如果确定需要在主线程中捕获它,则应使用子线程中的错误处理,然后通过使用一些同步化原语(例如Queue)将其发送到主线程。
import threading
from queue import Queue
class Checks:
@staticmethod
def isok(q):
print("OK")
@staticmethod
def isko(q):
try:
raise Exception("KO") # add error handling to the child thread
except:
q.put("ERROR_" + threading.current_thread().getName())
# db will keep a map of method names in Check with the actual (executable) method
db = {}
# create Queue for synchronization
q = Queue()
# 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), args=(q,))
db[check].start()
# wait for all the threads to be finished with error or not
for thread in db.keys():
db[thread].join()
# check if some threads were with errors and print the errors
if not q.empty():
while True:
x = q.get()
print(x)
if q.empty():
break
# all the threads are finished at that point
print("all threads are done")