键的替代散列 table 相等性测试
Alternative hash table equality testing for keys
SBCL 分析显示我的一个 Common Lisp 哈希 table 函数消耗了大量时间。该函数比较两个散列 table 以确定它们是否具有相同的键:
(defun same-keys (ht1 ht2)
"Returns t if two hash tables have the same keys."
(declare (hash-table ht1 ht2))
(when (= (hash-table-count ht1) (hash-table-count ht2))
(maphash (lambda (ht1-key ht1-value)
(declare (ignore ht1-value))
(unless (gethash ht1-key ht2)
(return-from same-keys nil)))
ht1)
t))
鉴于哈希 table 总是 #'eql
和 fixnum
键,有没有办法加快速度?我也在加载 lparallel
库,但在这种情况下以某种方式并行化函数是否有意义?
编辑:散列 tables 的大小可以在大约 10 到 100 个条目之间。 ht 键范围从 100 扩展到 999,999,999,999,但实际在这个范围内使用的总可能 fixnums 是稀疏的。每个 ht 值要么是 t 要么是一个列表。所有散列 table 的键值关联都是在加载时设置的。通过复制现有散列并逐步添加或删除条目,在 运行 时间创建了新散列 table。 routine hash table 读、写、复制好像都不是问题
除了低级优化外,它还取决于散列的大小-tables 和键值的可能范围。
如果键范围不比大小小很多,则使用向量而不是哈希-tables 可能会更快。如果大小很小(小于大约 20—50),但范围很大(例如 UUID),也许列表更适合。
如果写入这些 hash-tables 不是瓶颈,您可以将 hash-tables 与包含一些辅助数据结构的对象一起包装,以进行键比较。这可能是一些标记使用过的键的位向量,或者所有使用过的键的完整自定义散列,或者(如果大小和范围真的很大)像布隆过滤器。
如果您的问题在某些维度上足够大以致于值得付出开销,那么并行化可能是有意义的:例如,独立比较的频率非常高,或者每个散列的键数-table 很大。
一种可能的低级优化是使用 loop
而不是 maphash
,大多数情况下可以编译成更快的代码:
(loop :for key1 :being :the :hash-keys :of ht1
:always (nth-value 1 (gethash key1 ht2)))
SBCL 分析显示我的一个 Common Lisp 哈希 table 函数消耗了大量时间。该函数比较两个散列 table 以确定它们是否具有相同的键:
(defun same-keys (ht1 ht2)
"Returns t if two hash tables have the same keys."
(declare (hash-table ht1 ht2))
(when (= (hash-table-count ht1) (hash-table-count ht2))
(maphash (lambda (ht1-key ht1-value)
(declare (ignore ht1-value))
(unless (gethash ht1-key ht2)
(return-from same-keys nil)))
ht1)
t))
鉴于哈希 table 总是 #'eql
和 fixnum
键,有没有办法加快速度?我也在加载 lparallel
库,但在这种情况下以某种方式并行化函数是否有意义?
编辑:散列 tables 的大小可以在大约 10 到 100 个条目之间。 ht 键范围从 100 扩展到 999,999,999,999,但实际在这个范围内使用的总可能 fixnums 是稀疏的。每个 ht 值要么是 t 要么是一个列表。所有散列 table 的键值关联都是在加载时设置的。通过复制现有散列并逐步添加或删除条目,在 运行 时间创建了新散列 table。 routine hash table 读、写、复制好像都不是问题
除了低级优化外,它还取决于散列的大小-tables 和键值的可能范围。
如果键范围不比大小小很多,则使用向量而不是哈希-tables 可能会更快。如果大小很小(小于大约 20—50),但范围很大(例如 UUID),也许列表更适合。
如果写入这些 hash-tables 不是瓶颈,您可以将 hash-tables 与包含一些辅助数据结构的对象一起包装,以进行键比较。这可能是一些标记使用过的键的位向量,或者所有使用过的键的完整自定义散列,或者(如果大小和范围真的很大)像布隆过滤器。
如果您的问题在某些维度上足够大以致于值得付出开销,那么并行化可能是有意义的:例如,独立比较的频率非常高,或者每个散列的键数-table 很大。
一种可能的低级优化是使用 loop
而不是 maphash
,大多数情况下可以编译成更快的代码:
(loop :for key1 :being :the :hash-keys :of ht1
:always (nth-value 1 (gethash key1 ht2)))