密钥的替代哈希表相等性测试

时间:2019-02-17 19:42:12

标签: parallel-processing mapping common-lisp hashtable

SBCL分析显示我的Common Lisp哈希表功能之一正在消耗大量时间。该函数比较两个哈希表以确定它们是否具有相同的键:

(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))

考虑到哈希表始终是#'eqlfixnum键,是否有一种方法可以加快速度?我也在加载lparallel库,但是在这种情况下以某种方式并行化函数是否有意义?

编辑:哈希表的大小范围可以从10到100个条目。 ht键的范围从100扩展到999,999,999,999,但是此范围中实际使用的总Fixnum稀疏。每个ht值要么是t,要么是一个列表。所有哈希表的键值关联在加载时设置。通过复制现有哈希表并逐步添加或删除条目,可以在运行时创建新的哈希表。常规的哈希表读取,写入和复制似乎不是问题。

1 个答案:

答案 0 :(得分:5)

除底层优化外,它还取决于哈希表的大小和键值的可能范围。

如果键范围不小于大小,则使用向量而不是哈希表可能会更快。如果大小较小(小于20-50),但范围较大(例如UUID),则列表更适合。

如果写入这些哈希表不是瓶颈,则可以使用包含一些辅助数据结构的对象包装哈希表,以进行键比较。这可能是一些标记了已用密钥的位向量,或者是所有已用密钥的完整自定义哈希值,或者(如果大小和范围确实很大)诸如Bloom过滤器之类的东西。

如果您的问题在某个维度上足够大以至于值得承担开销,那么并行化可能有意义:例如,独立比较的频率很高,或者每个哈希表的键数很大。 >

一种可能的低级优化是使用loop而不是maphash,大多数情况下可以将其编译为更快的代码:

(loop :for key1 :being :the :hash-keys :of ht1
      :always (nth-value 1 (gethash key1 ht2)))