2016-09-14 43 views
0

如果字典在迭代过程中使用iteritems()更改其大小,Python会引发异常。是python dict.items()线程安全吗?

我对这个问题打,因为我的计划是多线程和有我需要遍历dict而另一个线程正在添加键进入dict案件。

幸运的是,我不需要迭代对dict中的每个元素都非常精确。因此,我在考虑使用items()而不是iteritems()来进行迭代。我认为items()会制作dict的静态快照,我会解决该问题。

我的问题是:items()如果dict大小与items()执行同时发生更改会引发异常?

感谢

+1

我的建议:如有疑问,请使用锁定:-) – mgilson

+0

推测项目()必须遍历字典,作为构建其快照的一部分。所以调用items()不会解决问题,只会将代码中的问题转移到items()方法的实现中。更好的解决方案是使用互斥锁序列化对字典的访问。 –

+0

http://effbot.org/pyfaq/what-kinds-of-global-value-mutation-are-thread-safe.htm说dict.keys()是原子的,我很奇怪items()是不。在同一篇文章中,它说“L1 [i:j] = L2”不是原子,而是“L [i] = L [j]”,这也很奇怪。我可以相信那篇文章吗? – abemaw

回答

0

的优秀评论中指出:

  1. 这不是线程安全的。

  2. 你在做这些事情时应该真的使用锁。

有可能看到这个the CPython source code, dictobject.c

如果你看一下它用于items功能

static PyObject * 
dict_items(register PyDictObject *mp) 

,你可以看到,(一些聪明的预分配后对于结果),它基本上遍历数组mp->ma_table(使用掩码来查看哪里有条目)。

现在,如果你看一下这是用来当表需要调整大小功能

static int 
dictresize(PyDictObject *mp, Py_ssize_t minused) 

,那么你就可以看到ma_table的元素可以移动到一个完全不同的缓冲,然后将其可以使用PYMem_Free来释放。

因此,如果事情没有同步并发完成,那么存在访问垃圾内存的风险。