安全地迭代WeakKeyDictionary和WeakValueDictionary

安全地迭代WeakKeyDictionary和WeakValueDictionary,第1张

安全地迭代WeakKeyDictionary和WeakValueDictionary

这是在实际安全的迭代

WeakKeyDictionary
WeakValueDictionary
WeakSet
在Python
2.7或Python
3.1+。他们引入了一个迭代保护措施,以防止弱引用回调从2010年以来的迭代过程中从底层dict或集合中删除引用,但是这些文档从未得到更新。

有了警惕,如果一个条目在迭代到达之前就死了,那么迭代将跳过该条目,但是不会导致segfault或RuntimeError或任何其他错误。无效条目将添加到挂起的删除列表中,并在以后处理。

这是警卫(尽管有评论,但不是线程安全的):

class _IterationGuard:    # This context manager registers itself in the current iterators of the    # weak container, such as to delay all removals until the context manager    # exits.    # This technique should be relatively thread-safe (since sets are).    def __init__(self, weakcontainer):        # Don't create cycles        self.weakcontainer = ref(weakcontainer)    def __enter__(self):        w = self.weakcontainer()        if w is not None: w._iterating.add(self)        return self    def __exit__(self, e, t, b):        w = self.weakcontainer()        if w is not None: s = w._iterating s.remove(self) if not s:     w._commit_removals()

这是WeakKeyDictionary弱引用回调检查防护的地方:

def remove(k, selfref=ref(self)):    self = selfref()    if self is not None:        if self._iterating: self._pending_removals.append(k)        else: del self.data[k]

这是

WeakKeyDictionary.__iter__
设置警卫的地方:

def keys(self):    with _IterationGuard(self):        for wr in self.data: obj = wr() if obj is not None:     yield obj__iter__ = keys

在其他迭代器中使用相同的防护。


如果没有这个守卫,打电话

list(d.items())
也不安全。GC遍历可能发生在
items
迭代器内部,并在迭代过程中从dict中删除项目。(
list
用C语言编写的事实不会提供任何保护。)


在2.6和更早的版本中,迭代WeakKeyDictionary或WeakValueDictionary的最安全方法是使用

items
items
会返回一个列表,并使用底层dict的
items
方法,该方法通常不会被GC中断(主要是?)。在3.0的字典API的变化而变化如何
keys
/
values
/
items
工作,这可能是为什么警卫被引入时,它是。



欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5649108.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-16
下一篇 2022-12-16

发表评论

登录后才能评论

评论列表(0条)

保存