窥探 Python 的集合数据结构内部

主要观点:性能工程中数据结构选择关键,以 Python 的 set 实现为例,讨论其数据模型及关键 API 实现,包括插入、查找、删除、弹出等操作,还涉及哈希表相关内容如哈希函数、碰撞处理技术(链式法和开放寻址法),并比较了两种技术的性能特点,同时介绍了 Python set 的内存布局、初始化过程及线程安全性等。
关键信息:

  • Python 的 set 用哈希表实现,平均情况常量时间查找,表满时性能可能下降。
  • 哈希函数需快速、均匀分布、最小相关,不讨论其实现细节但提及相关书籍。
  • 处理哈希表碰撞有链式法和开放寻址法,Python 的 set 采用线性探测(或线性探测与随机探测结合)。
  • Python set 的内存布局包含对象头、填充计数、使用计数、掩码、表指针等字段。
  • 插入新对象时先计算哈希,字符串有缓存哈希值优化,插入通过set_add_entry函数实现。
  • 移除对象先计算哈希,查找并标记为墓碑,查找过程与插入类似。
  • contains API 计算哈希并在哈希表中查找对象。
  • pop API 通过 finger 字段决定删除的元素,删除后更新 finger 值。
  • 之前 Python 的 set 因 GIL 线程安全不是问题,现在多线程 build 已使其线程安全,但不是真正并发,整个对象加锁可能导致竞争和饥饿。
    重要细节:
  • 掩码用于将哈希值映射到表大小范围,表大小为 2 的幂时用位与操作更高效。
  • 线性探测在表满时插入变慢,链式法插入快但额外内存开销大,查找慢。
  • 随机探测通过随机函数改变索引避免键聚类。
  • 不同 API 实现细节如计算哈希、查找和删除等过程的具体代码和逻辑。
阅读 26
0 条评论