【发布时间】:2017-12-21 09:28:37
【问题描述】:
CPython deque 是 implemented 作为 64 项大小的“块”(数组)的双向链表。块都是满的,除了链表两端的块。 IIUC,当 pop / popleft 删除块中的最后一项时,块被释放;它们在append/appendleft 尝试添加新项目并且相关块已满时分配。
我理解the listed advantages 使用块的链接列表而不是项目的链接列表:
- 减少每个项目中指向 prev 和 next 的指针的内存成本
- 为添加/删除的每个项目减少
malloc/free的运行时成本 - 通过将连续指针彼此相邻放置来提高缓存局部性
但为什么一开始不使用单个动态大小的循环数组来代替双向链表呢?
AFAICT,循环数组将保留上述所有优势,并将pop*/append* 的(摊销)成本维持在O(1)(通过过度分配,就像在list 中一样)。此外,它将按索引查找的成本从当前的O(n) 提高到O(1)。循环数组也更容易实现,因为它可以重用大部分 list 实现。
我可以在 C++ 等语言中看到支持链表的论点,其中可以在 O(1) 中使用指针或迭代器从中间删除项目;但是,python deque 没有 API 可以做到这一点。
【问题讨论】:
-
链表没有引人注目的优势。除非有人能挖掘出相关的邮件列表讨论或其他内容,否则我们所能做的就是将其归结为
collections.deque推出时某个人的心血来潮。 -
根据这个问题的结果,也许可以实现您的想法,针对 CPython 测试运行它,进行一些基准测试,然后提交拉取请求。
-
@user2357112 我会同意你的看法,但有问题的人是超级熟练的,并且在没有仔细分析的情况下从不做任何事情:)
-
挖掘Raymond Hettinger's
collectionsmodule proposal to Python-Dev,这可能是关于collections.deque的第一个公开讨论之一,没有给出链表结构的理由,我也没有看到任何讨论它的回复。最接近基本原理的是“就像我们用于 itertools.tee() 一样”,这表明他们可能想重用现有代码(对双链接进行修改)。 -
This 来自 RDH 的消息似乎是您问题的答案,不像您可能想要的那样冗长。 previous message 讨论了替代实现。
标签: python python-3.x cpython python-internals