3

我正在编写一种方法来生成缓存键以用于缓存函数结果,该键基于函数名称和参数哈希值的组合。

目前我正在使用 hashlib 对参数的序列化版本进行哈希处理,但是序列化大对象的操作非常昂贵,那么有什么替代方案呢?

#get the cache key for storage
def cache_get_key(*args):
    import hashlib
    serialise = []
    for arg in args:
        serialise.append(str(arg))
    key = hashlib.md5("".join(serialise)).hexdigest()
    return key

更新:我尝试使用 hash(str(args)),但是如果 args 中有相对较大的数据,仍然需要很长时间来计算哈希值。有什么更好的方法吗?

实际上,具有大数据的 str(args) 需要永远......

4

5 回答 5

1

您是否尝试过仅使用该hash功能?它在元组上效果很好。

于 2012-04-10T21:58:11.040 回答
1

假设您创建了对象,并且它由较小的组件组​​成(它不是二进制 blob),您可以在构建对象时使用其子组件的哈希值预先计算哈希值。

例如,而不是serialize(repr(arg)),做arg.precomputedHash if isinstance(arg, ...) else serialize(repr(arg))

如果您既不制作自己的对象也不使用hash可用的对象,您也许可以保留一个对象引用的记忆表 -> 哈希,假设您不改变对象。最坏的情况是,您可以使用允许记忆的函数式语言,因为这种语言中的所有对象都可能是不可变的,因此是可散列的。

于 2012-04-10T22:03:11.633 回答
1
def cache_get_key(*args):
    return hash(str(args))

或者(如果你真的想使用 hashlib 库)

def cache_get_key(*args):
    return hashlib.md5(str(args)).hexdigest()

我不会费心重写代码来将数组变成字符串。使用内置的。

替代解决方案

以下是@8bitwide 建议的解决方案。此解决方案根本不需要散列!

def foo(x, y):
    return x+y+1

result1 = foo(1,1)
result2 = foo(2,3)

results = {}
results[foo] = {}
results[foo][ [1,1] ] = result1
results[foo][ [2,3] ] = result2
于 2012-04-10T22:05:14.637 回答
0

我见过人们将任意 python 对象提供给 random.seed(),然后使用从 random.random() 返回的第一个值作为“散列”值。它并没有给出极好的值分布(可以倾斜),但它似乎适用于任意对象。

如果您不需要加密强度的哈希,我想出了一对哈希函数,用于我在布隆过滤器中使用的整数列表。它们出现在下方。布隆过滤器实际上使用这两个散列函数的线性组合来获得任意数量的散列函数,但它们应该在其他只需要一些散布并具有良好分布的情况下工作正常。它们的灵感来自 Knuth 关于线性同余随机数生成的文章。他们将整数列表作为输入,我相信这可能只是您的序列化字符的 ord()。

MERSENNES1 = [ 2 ** x - 1 for x in [ 17, 31, 127 ] ]
MERSENNES2 = [ 2 ** x - 1 for x in [ 19, 67, 257 ] ]


def simple_hash(int_list, prime1, prime2, prime3):
    '''Compute a hash value from a list of integers and 3 primes'''
    result = 0
    for integer in int_list:
        result += ((result + integer + prime1) * prime2) % prime3
    return result


def hash1(int_list):
    '''Basic hash function #1'''
    return simple_hash(int_list, MERSENNES1[0], MERSENNES1[1], MERSENNES1[2])


def hash2(int_list):
    '''Basic hash function #2'''
    return simple_hash(int_list, MERSENNES2[0], MERSENNES2[1], MERSENNES2[2])
于 2012-04-10T22:43:21.800 回答
0

我知道这个问题很老,但我只想加上我的 2 美分:

  1. 您不必创建一个列表然后加入它。特别是如果列表无论如何都会被丢弃。使用哈希函数的.update()方法

  2. 考虑使用更快的非加密哈希算法,特别是如果这不是加密安全的实现。

话虽如此,这是我建议的改进:

import xxhash

#get the cache key for storage
def cache_get_key(*args):
    hasher = xxhash.xxh3_64()
    for arg in args:
        hasher.update(str(arg))
    return hasher.hexdigest()

这使用(声称是)极快的xxHash NCHF*


* NCHF = 非加密哈希函数

于 2021-10-06T15:48:18.313 回答