主要观点:性能工程中数据结构选择关键,以 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 实现细节如计算哈希、查找和删除等过程的具体代码和逻辑。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用。你还可以使用@来通知其他用户。