2012-02-25 143 views
3

我目前正在编程一个基于python的数据报服务器使用线程和所有这些。Python:'thread._local对象没有属性'todo'

我遇到了以下问题:我正在使用多个分配线程将传入的包分配给不同的处理线程。在处理线程中,我使用threading.local()跟踪线程局部变量。

我目前正在测试我的服务器在高负载(大约2秒内2000个数据包)期间的反应,并且出现了local() - Object的奇怪行为。

好像它工作得很好了一会儿,然后,在某些时候,它抛出一个异常:

Exception in thread 192.168.1.102: # <-- This is the Processing Thread 
Traceback (most recent call last): 
    File "/opt/lib/python2.7/threading.py", line 552, in __bootstrap_inner 
    self.run() 
    File "/volume1/home/Max/Python/MyThread/pyProcThread.py", line 37, in run 
    print self.loc.father 
AttributeError: 'thread._local' object has no attribute 'father' 

# The following three lines are debug 
# This is the Allocation thread that has called the Processing thread 
<Thread(192.168.1.102, started 1106023568)> 
# This confirms that the queue it tries to access exists 
<Queue.Queue instance at 0x40662b48> 
# This is the Processing thread, which has stopped executing on exception 
<Thread(192.168.1.102, stopped 1106023568)> 

Exception in thread pyAlloc-0: # <-- This is the Allocation thread 
Traceback (most recent call last): 
    File "/opt/lib/python2.7/threading.py", line 552, in __bootstrap_inner 
    self.run() 
    File "/volume1/home/Max/Python/MyThread/pyAllocThread.py", line 60, in run 
    foundThread.addTask(str(data)) 
    File "/volume1/home/Max/Python/MyThread/pyProcThread.py", line 58, in addTask 
    print self.loc.todo 
AttributeError: 'thread._local' object has no attribute 'todo' 

处理线程

# Imports 
import threading 
import time 
import Queue 

class Thread(threading.Thread): 
    def __init__(self,pThread): 
     threading.Thread.__init__(self) 
     self.loc = threading.local() 
     self.loc.todo = Queue.Queue() 
     self.loc.father = pThread 
     print "Konstruktor ausgefuehrt" 
     print self.loc.todo 

    def run(self): 
     self.loc.run = True; 
     print self.loc.father 
     while (self.loc.run): 
     try: 
      task = self.loc.todo.get(True, 1) 
      print "processing..." 
      if(task == self): 
       self.loc.run=False 
      else: 
       print task 
     except Queue.Empty: 
      pass 
     self.loc.father.threadTerminated(self) 
     print self.name, "terminating..." 

    def addTask(self, pTask): 
     print self 
     print self.loc.todo 
     self.loc.todo.put(pTask) 

而分配的一部分线程:

import threading 
import pyProcThread # My processing Thread 
import Queue 
import time 
class Thread(threading.Thread): 
    # Lock-Objects 
    threadListLock = threading.Lock() 
    waitListLock = threading.Lock() 

    alive = True; 

    taskQueue = Queue.Queue() 
    # Lists 
    # List of all running threads 
    threads = [] 

    def threadExists(self,pIP): 
     """Checks if there is already a thread with the given Name""" 
     for x in self.threads: 
      if x.name == pIP: 
       return x 
     return None 

    def threadTerminated(self,pThread): 
     """Called when a Processing Thread terminates""" 
     with self.threadListLock: 
      self.threads.remove(pThread) 
      print "Thread removed" 

    def threadRegistered(self,pThread): 
     """Registers a new Thread""" 
     self.threads.append(pThread) 

    def killThread(self): 
     self.alive = False 

    def run(self): 
     while(self.alive): 
      # print "Verarbeite Nachricht ", self.Message 
      # print "Von ", self.IP 
      try: 
       data, addtemp = self.taskQueue.get(True, 1) 
       addr, _junk = addtemp 
       with self.threadListLock: 
        foundThread=self.threadExists(str(addr)) 
        # print "Thread " + self.name + " verarbeitet " + data 
        if (foundThread!=None): 
         #print "recycling thread" 
         foundThread.addTask(str(data)) 
        else: 
         print "running new Thread" 
         t = pyProcThread.Thread(self) 
         t.name = str(addr) 
         t.addTask(str(data)) 
         t.start() 
         self.threadRegistered(t) 
       self.taskQueue.task_done() 
      except Queue.Empty: 
       pass 
     print self.name, "terminating..." 
     with self.threadListLock: 
      for thread in self.threads: 
       thread.addTask(thread) 

全输出,包括所有调试打印的:

running new Thread 
Konstruktor ausgefuehrt 
<Queue.Queue instance at 0x40662b48> 
<Thread(192.168.1.102, initial)> 
<Queue.Queue instance at 0x40662b48> 
<Thread(192.168.1.102, started 1106023568)> 
<Queue.Queue instance at 0x40662b48> 
<Thread(192.168.1.102, started 1106023568)> 
<Queue.Queue instance at 0x40662b48> 
<Thread(192.168.1.102, started 1106023568)> 
<Queue.Queue instance at 0x40662b48> 
<Thread(192.168.1.102, started 1106023568)> 
<Queue.Queue instance at 0x40662b48> 
<Thread(192.168.1.102, started 1106023568)> 
<Queue.Queue instance at 0x40662b48> 
<Thread(192.168.1.102, started 1106023568)> 
<Queue.Queue instance at 0x40662b48> 
<Thread(192.168.1.102, started 1106023568)> 
<Queue.Queue instance at 0x40662b48> 
Exception in thread 192.168.1.102: 
Traceback (most recent call last): 
    File "/opt/lib/python2.7/threading.py", line 552, in __bootstrap_inner 
    self.run() 
    File "/volume1/home/Max/Python/MyThread/pyProcThread.py", line 37, in run 
    print self.loc.father 
AttributeError: 'thread._local' object has no attribute 'father' 

<Thread(192.168.1.102, started 1106023568)> 
<Queue.Queue instance at 0x40662b48> 
<Thread(192.168.1.102, stopped 1106023568)> 
Exception in thread pyAlloc-0: 
Traceback (most recent call last): 
    File "/opt/lib/python2.7/threading.py", line 552, in __bootstrap_inner 
    self.run() 
    File "/volume1/home/Max/Python/MyThread/pyAllocThread.py", line 60, in run 
    foundThread.addTask(str(data)) 
    File "/volume1/home/Max/Python/MyThread/pyProcThread.py", line 58, in addTask 
    print self.loc.todo 
AttributeError: 'thread._local' object has no attribute 'todo' 

Terminating main 
192.168.1.102 
DEINEMUDDA sent to 192.168.1.102 : 8082 
pyAlloc-1 terminating... 
<Thread(192.168.1.102, stopped 1106023568)> 
<Queue.Queue instance at 0x40662b48> 

正如你可以在日志中看到,一切似乎都很好地工作了一段时间,但它从来没有达到在加工螺纹的主要功能print "processing

我已经搜索了网络和StackOverflow的类似问题,但无法找到任何。预先感谢任何帮助,并且原谅我的编码风格,我现在只编程Python几天,仍然学习它的一些功能。

编辑:当然,这个服务器比这更多。有一个主线程正在接收数据包并将它们发送到分配线程以及后台的其他一些东西。另外,服务器远没有完成,但我想在开始其他事情之前让接收工作。

回答

5

threading.local是表示线程本地数据的类。线程本地数据是其值为线程特定的数据,因此仅适用于本地线程(创建local()对象的线程)。换句话说,只有设置该值的线程才会看到该值。

由于您在处理线程的__init__方法中设置了loc.parent值,但在分配器线程内部执行,所以只能在分配器线程中使用线程处理线程的本地线程。所以它在处理线程的run()中将不起作用,因为它将由不同的线程(不是分配器)执行。

+0

这很有趣,谢谢。如果我删除'print self.loc.parent',他也有'self.loc.todo'问题。我想这有同样的道理。我怎样才能做到这一点(将'parent'和'todo'属性放入'loc'中,这两个属性都可以在处理线程中访问)?是否有一个python帮助页面详细解释了这个整个机制?再次感谢。 – malexmave 2012-02-25 18:37:48

+0

您可以将值设置为'Thread'对象的常规属性,所以'self.father = pThread'。我相信父不是执行线程特定的,而是线程实例特定的。 – 2012-02-25 18:40:18

+0

呃,那实际上是我的工作解决方案,我试图用本地对象“正确”。但是因为它看起来像是“自我”。属性'似乎是正确的方式,我可以继续使用它(它感觉像是一个肮脏的解决方法,因为我第一次尝试时无法让本地对象工作)。再次感谢。 – malexmave 2012-02-25 18:43:42