2014-09-12 72 views
1

我目前正在开发一个python机器人,其中我有一些带有迭代器方法的类的代码。迭代器冻结

buffer = [] 
def __iter__(self): 
    return self 
def __next__(self): 
    incoming = str(self.irc.recv(1024), encoding='utf-8').split("\r\n") 
    self.buffer += incoming 
    last = self.buffer.pop(0) #This implements a FI-FO queue 
    #perform operations to extract commands etc. 
    return [message,command,trail] 

我打电话的这个类中的迭代器基本上是这样的:

for command in connection: #Connection is the name of the above class 
    print(command) 

什么,我观察到的是,队列的第3个元素是通过迭代,然后剩下的只是留在那里,在队列中,直到一个新元素进入队列时才处理,此时队列中的第一个元素将离开(就像最后一个元素推出第一个元素一样)。 我不确定这是否与迭代器有关,并且我不应该使用它们来执行此任务(如果不是,那么应该使用什么),或者这是否是另一个问题。感谢您的帮助,Kunc。

+2

'irc.recv'看起来像是可能导致线程阻塞的事情,请确保您没有等待数据。 – user2085282 2014-09-12 23:51:41

+1

你真的想把'buffer'作为一个类属性,由这个类的所有实例共享吗?对于像这样的东西,这似乎是一个非常糟糕的主意...... – abarnert 2014-09-13 01:26:44

+1

是的。我现在通过在recv函数中添加if语句来检查缓冲区是否为空,然后再添加它。 – Kunc 2014-09-13 01:33:42

回答

3

你的主要问题是:

每次推进你的迭代器的时候,你recv一行或多行,然后return只是其中的最后一个。所以在某些时候,你会把所有的行都堆积在你的队列中,然后尝试接收另一大块数据,这些数据不会出现,所以你会永远阻止。

想象对方发送的这三个缓冲区:

'abc\ndef\nghi\n' 
'jkl\n' 
'mno\nprs\n' 

所以,第一次通过,您会收到'abc\ndef\nghi\n',拆分成三行,并返回'abc'

第二次,您会收到'jkl\n',将其分成多行并追加,并返回'def'

第三次,您将收到'mno\nprs\n',将其分成两行并附加它们,并返回'ghi'

第四次,你会永远等待接收下一行。

你需要在这里做的不是recv,直到你不合格。


但是,您有第二个问题。绝对没有任何事情可以保证每个缓冲区都以换行符结束。所以你可以很容易地把线分成两半。你想要做的是这样的:

def __init__(self): 
    self.lines, self.buf = [], '' 
    # existing code 
def __next__(self): 
    if not self.lines: 
     newbuf = str(self.irc.recv(1024), encoding='utf-8') 
     if newbuf: 
      self.buf += newbuf 
      self.lines = self.buf.split("\r\n") 
      self.buf = self.lines.pop() 
    last = self.lines.pop(0) 
    # etc. 

或者更简单地说:

def __init__(self): 
    # existing code 
    self.rfile = self.irc.makefile('r', encoding='utf-8', newline='\r\n') 
def close(self): 
    self.rfile.close() 
    # existing code 
def __next__(self): 
    return self.rfile.readline() 

因为我写的代码是什么socket.makefile呢,除了它包装起来在一个完整的类文件对象中(在这种情况下为io.TextIOWrapper)。