如何在 Python 中使用队列处理线程中的异常? [英] How to handle exception in threading with queue in Python?

查看:49
本文介绍了如何在 Python 中使用队列处理线程中的异常?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

This is never print: "Exception in threadfuncqueue handled by threadfuncqueue", "Exception in threadfuncqueue handled by main thread" and "thread test with queue passed". Never quitting!

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()

如何处理这个异常?

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

Example of worked code, but without queue:

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 ==========="

推荐答案

简答

您将事物放入队列并检索它们,但是如果您要加入队列,则需要在将任务从队列中拉出并处理它们时将其标记为已完成.根据文档,每次将item,计数器递增,您需要调用 q.task_done() 来递减该计数器.q.join() 将阻塞,直到计数器达到零.在 q.get() 调用后立即添加它以防止 main 被阻塞:

Short Answer

You're putting things in a queue and retrieving them, but if you're going to join a queue, you need to mark tasks as done as you pull them out of the queue and process them. According to the docs, every time you enqueue an item, a counter is incremented, and you need to call q.task_done() to decrement that counter. q.join() will block until that counter reaches zero. Add this immediately after your q.get() call to prevent main from being blocked:

q.task_done()

另外,我觉得奇怪的是,您在 q 中检查空性 之后您从中检索到了一些东西.我不确定您到底想通过它实现什么目标,因此我没有给您任何建议,但我建议您重新考虑您在该领域的设计.

Also, I find it odd that you're checking q for emptiness after you've retrieved something from it. I'm not sure exactly what you're trying to achieve with that so I don't have any recommendations for you, but I would suggest reconsidering your design in that area.

一旦你让这段代码工作起来,你应该把它交给代码审查,因为它有点乱.这里有一些想法供您参考:

Once you get this code working you should take it over to Code Review because it is a bit of a mess. Here are a few thoughts for you:

您实际上并未处理"threadfuncqueue(q) 中的异常.finally 语句所做的就是允许您在发生异常时执行清理代码.它实际上并不捕获和处理异常.异常仍将沿调用堆栈向上移动.考虑这个例子,test.py:

You're not actually "handling" the exception in threadfuncqueue(q). All the finally statement does is allow you to execute cleanup code in the event of an exception. It does not actually catch and handle the exception. The exception will still travel up the call stack. Consider this example, test.py:

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

输出:

是的!
回溯(最近一次调用最后一次):
   文件test.py",第 2 行,在
       引发异常
异常

Yup!
Traceback (most recent call last):
    File "test.py", line 2, in
        raise Exception
Exception

注意是的!"打印时不!"没有.finally 块中的代码被执行,但这并没有阻止异常向上传播堆栈并停止解释器.您需要 except 语句:

Notice that "Yup!" got printed while "Nope!" didn't. The code in the finally block was executed, but that didn't stop the exception from propagating up the stack and halting the interpreter. You need the except statement for that:

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

输出:

是的!
不行!

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

This time both are printed, because we caught and handled the exception.

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

Your current method of raising the exception in your thread is needlessly complicated. Instead of creating the whole ImRaiseError class, just raise the exception you want with a string:

raise Exception('Whatever error message I want')

如果您发现自己手动操作了错位名称(比如self.__class__.__name__),你通常做错了什么.

If you find yourself manually manipulating mangled names (like self.__class__.__name__), you're usually doing something wrong.

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

Using parentheses around conditional expressions is generally frowned upon in Python:

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

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

Try to break the C/C++/Java habit and get rid of them:

if 1 == i:

其他

我已经超出了这个问题的范围,所以我现在要结束这个问题,但是还有一些其他的事情你可以清理并变得更惯用.完成此处后前往代码审查,看看还有哪些地方可以改进.

Other

I've already gone beyond the scope of this question, so I'm going to cut this off now, but there are a few other things you could clean up and make more idiomatic. Head over to Code Review when you're done here and see what else can be improved.

这篇关于如何在 Python 中使用队列处理线程中的异常?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆