【问题标题】:How to handle exception in threading with queue in Python?如何在 Python 中使用队列处理线程异常?
【发布时间】:2014-08-08 09:26:21
【问题描述】:

这从不打印: "threadfuncqueue 处理的 threadfuncqueue 中的异常", “主线程处理的线程函数队列中的异常”和 “通过队列的线程测试”。永不放弃!

from threading import Thread
from Queue import Queue
import time

class ImRaiseError():
    def __init__(self):
        time.sleep(1)
        raise Exception(self.__class__.__name__)

# place for paste worked code example from below 

print "begin thread test with queue"
def threadfuncqueue(q):
    print "\n"+str(q.get())
    while not q.empty():
        try:
            testthread = ImRaiseError()
        finally:
            print "Exception in threadfuncqueue handled by threadfuncqueue"

q = Queue()
items = [1,2]
for i in range(len(items)):
     t = Thread(target=threadfuncqueue,args=(q,))
     if(1 == i):
        t.daemon = False
     else:
        t.daemon = True
     t.start()
for item in items:
    q.put("threadfuncqueue"+str(item))

try:
    q.join()       # block until all tasks are done
finally:
    print "Exception in threadfuncqueue handled by main thread"
print "thread test with queue passed"
quit()

如何处理这个异常?

工作代码示例,但没有队列:

print "=========== procedure style test"
def threadfunc(q):
    print "\n"+str(q)
    while True:
        try:
            testthread = ImRaiseError()
        finally:
            print str(q)+" handled by process"

try:
    threadfunc('testproc')
except Exception as e:
    print "error!",e
print "procedure style test ==========="


print "=========== simple thread tests"
testthread = Thread(target=threadfunc,args=('testthread',))
testthread.start()
try:
    testthread.join()
finally:
    print "Exception in testthread handled by main thread"
testthread1 = Thread(target=threadfunc,args=('testthread1',))
testthread1.start()
try:
    testthread1.join()
finally:
    print "Exception in testthread1 handled by main thread"
print "simple thread tests ==========="

【问题讨论】:

    标签: python multithreading queue


    【解决方案1】:

    简答

    您将任务放入队列并检索它们,但如果您要加入队列,则需要在将任务从队列中拉出并处理它们时将它们标记为已完成。 According to the docs,每次入队时,计数器都会递增,您需要调用 q.task_done() 来递减该计数器。 q.join() 将阻塞,直到该计数器达到零。在您的 q.get() 调用之后立即添加它以防止 main 被阻止:

    q.task_done()
    

    另外,我觉得奇怪的是,您在从 q 检索到某些内容之后, 又检查了它是否为空。我不确定你到底想达到什么目的,所以我没有给你任何建议,但我建议重新考虑你在该领域的设计。

    其他想法

    一旦你得到这个代码,你应该把它交给Code Review,因为它有点乱。这里有一些想法供您参考:

    异常处理

    您实际上并没有“处理”threadfuncqueue(q) 中的异常。 finally 语句所做的只是允许您在发生异常时执行清理代码。它实际上并没有捕获和处理异常。异常仍将沿调用堆栈向上传播。考虑这个例子,test.py:

    try:
        raise Exception
    finally:
        print("Yup!")
    print("Nope!")
    

    输出:

    是的!
    回溯(最近一次通话最后一次):
    文件“test.py”,第 2 行,在
    引发异常
    异常

    请注意,“是的!”在“不!”时被打印出来。没有。 finally 块中的代码已执行,但这并没有阻止异常向上传播堆栈并停止解释器。为此,您需要 except 声明:

    try:
        raise Exception
    except Exception: # only catch the exceptions you expect
        print("Yup!")
    print("Nope!")
    

    输出:

    是的!
    不!

    这次都打印了,因为我们捕获并处理了异常。

    异常引发

    您当前在线程中引发异常的方法过于复杂。无需创建整个 ImRaiseError 类,只需使用字符串引发您想要的异常:

    raise Exception('Whatever error message I want')
    

    如果您发现自己手动操作了mangled names(如self.__class__.__name__),那么您通常做错了什么。

    额外的括号

    在 Python 中通常不赞成在条件表达式周围使用括号:

    if(1 == i): # unnecessary extra characters 
    

    尝试打破 C/C++/Java 的习惯并摆脱它们:

    if 1 == i:
    

    其他

    我已经超出了这个问题的范围,所以我现在要切断它,但还有一些其他的事情你可以清理并变得更惯用。完成后前往代码审查,看看还有什么可以改进的。

    【讨论】:

      猜你喜欢
      • 2013-09-10
      • 2010-10-23
      • 2020-04-17
      • 1970-01-01
      • 1970-01-01
      • 2013-02-27
      • 1970-01-01
      • 2011-10-15
      • 2016-01-17
      相关资源
      最近更新 更多