它给了我这个错误:
Exception in thread Thread-163:
Traceback (most recent call last):
File "C:\Python26\lib\threading.py", line 532, in __bootstrap_inner
self.run()
File "C:\Python26\lib\threading.py", line 736, in run
self.function(*self.args, **self.kwargs)
File "C:\Users\Public\SoundLog\Code\Código Python\SoundLog\SoundLog.py", line 337, in getInfo
self.data1 = copy.deepcopy(Auxiliar.DataCollection.getInfo(1))
File "C:\Python26\lib\copy.py", line 162, in deepcopy
y = copier(x, memo)
File "C:\Python26\lib\copy.py", line 254, in _deepcopy_dict
for key, value in x.iteritems():
RuntimeError: dictionary changed size during iteration
执行我的python程序时。
我怎样才能避免这种情况发生?
提前致谢;)
答案 0 :(得分:13)
根据其他答案,正常建议是避免使用iteritems
(改为使用items
)。当然,在您的情况下,不是一个选项,因为iteritems
电话是在您的系统调用的深处代表您完成的。
因此,我建议,假设Auxiliar.DataCollection.getInfo(1)
返回字典(在复制过程中正在更改的字典)是您将deepcopy
调用更改为:
self.data1 = copy.deepcopy(dict(Auxiliar.DataCollection.getInfo(1)))
这会拍摄相关字典的“快照”,快照不会改变,所以你会没事的。
如果Auxiliar.DataCollection.getInfo(1)
不返回一个字典,而是一些更复杂的对象,其中包含dicts作为项目和/或属性,那将会更复杂一些,因为那些dicts是什么你需要快照。但是,在这种情况下,不可能更具体,因为你完全不知道组成那个关键的Auxiliar.DataCollection.getInfo(1)
调用的代码! - )
答案 1 :(得分:2)
虽然这个帖子已有近2年的历史,但我遇到了类似的问题:
我有一个基于Queue模块的类似生产者/消费者的系统。我的工人级'run-method定义如下:
def run(self):
while True:
a, b, c = Worker._Queue.get()
# do some stuff
...
self.notify() # notify observers
Worker._Queue.task_done()
main-class定义了一个update-method,用于通知工作者收集数据并将其存储在字典中。由于多个线程可能会更改主类中的字典,因此“关键部分”被锁定
def update(self, worker):
Main.indexUpdateLock.acquire()
# get results of worker
index = worker.getIndex()
# copy workers index into the main index
try:
for i in index:
if i in self._index:
self._index[i] += index[i]
else:
self._index[i] = index[i]
finally:
# index copied - release the lock
Main.indexUpdateLock.release()
现在这在大多数情况下都有效 - 但是在某些情况下,有时候'对于我在索引中:'在主的update-method中会抛出一个RuntimeError:字典在迭代期间改变了大小。 indexUpdateLock定义为threading.Lock()或threading.RLock() - 行为不会改变我定义它的方式。
for d in dict(index):确实解决了问题,但由于索引可能包含数千个条目,复制它并不会真正提高性能,因此我试图直接复制这些值。
虽然更新是在Main中定义的,但是通过在worker的线程中调用notify(),update也应该在worker的线程中执行,因此task_done()只有在notify()或更新后的update()完成时才会执行处理。通过临界区的定义,一次只允许一个线程执行该区域 - 或者我在这里有一些逻辑错误?我真的没有看到工作者索引的更改来自哪里,因为唯一的索引访问权限是在Main.update()和Worker中,但是直到task_done()没有执行,没有其他方法修改工作者内部的索引
编辑: 好的,修复了由于发送了一个额外条目的工作者内部的HTMLParser引起的问题,尽管源已经关闭 - 虽然有奇怪的行为。虽然对于索引中的i:仍然在index.keys()中为i生成错误:没有,所以我会坚持这个
答案 2 :(得分:0)
听起来您正在尝试迭代的字典中添加或删除某些内容。大多数语言都不允许这样做。