您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

安全地迭代WeakKeyDictionary和WeakValueDictionary

安全地迭代WeakKeyDictionary和WeakValueDictionary

这是在实际安全的迭代WeakKeyDictionaryWeakValueDictionaryWeakSet在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的最安全方法是使用itemsitems会返回一个列表,并使用底层dict的items方法,该方法通常不会被GC中断(主要是?)。在3.0的字典API的变化而变化如何keys/values/items工作,这可能是为什么警卫被引入时,它是。

其他 2022/1/1 18:40:02 有454人围观

撰写回答


你尚未登录,登录后可以

和开发者交流问题的细节

关注并接收问题和回答的更新提醒

参与内容的编辑和改进,让解决方法与时俱进

请先登录

推荐问题


联系我
置顶