【发布时间】:2017-01-23 17:08:08
【问题描述】:
我已经有一个运行良好的记忆器。它使用 pickle 转储序列化输入并创建 MD5 哈希作为键。函数结果非常大,并存储为文件名为 MD5 哈希的 pickle 文件。当我一个接一个地调用两个 memoized 函数时,memoizer 将加载第一个函数的输出并将其传递给第二个函数。第二个函数将序列化它,创建 MD5,然后加载输出。这是一个非常简单的代码:
@memoize
def f(x):
...
return y
@memoize
def g(x):
...
return y
y1 = f(x1)
y2 = g(y1)
y1 在评估f 时从磁盘加载,然后在评估g 时对其进行序列化。是否有可能以某种方式绕过这一步并将y1 的密钥(即MD5 哈希)传递给g?如果g 已经有这个密钥,它会从磁盘加载y2。如果没有,它会“请求”完整的y1 以评估g。
编辑:
import cPickle as pickle
import inspect
import hashlib
class memoize(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
arg = inspect.getargspec(self.func).args
file_name = self._get_key(*args, **kwargs)
try:
f = open(file_name, "r")
out = pickle.load(f)
f.close()
except:
out = self.func(*args, **kwargs)
f = open(file_name, "wb")
pickle.dump(out, f, 2)
f.close()
return out
def _arg_hash(self, *args, **kwargs):
_str = pickle.dumps(args, 2) + pickle.dumps(kwargs, 2)
return hashlib.md5(_str).hexdigest()
def _src_hash(self):
_src = inspect.getsource(self.func)
return hashlib.md5(_src).hexdigest()
def _get_key(self, *args, **kwargs):
arg = self._arg_hash(*args, **kwargs)
src = self._src_hash()
return src + '_' + arg + '.pkl'
【问题讨论】:
-
为什么不为两个函数使用一个命名空间?我的意思是你应该为两者使用一个基于键值的文件(如 json 等)。
-
目前的方法到底有什么问题?是否(几乎)相同的大数据块在磁盘上保存了两次?如果这两个功能之一只是做“便宜”的东西,不要
@memoize它;否则,我认为没有什么好办法。 -
@MSeifert 这是一个非常简化的示例,我拥有一整套函数,它们使用一个的输出作为另一个的输入。所以将其转换为
g(f(x))并不总是那么容易。 -
函数评估非常昂贵,从磁盘加载作为序列化更便宜。但是,数据集非常大,所以如果我能避免不必要的 I/O 和序列化,它会进一步加快我的代码速度。
-
能否提供
memoize的实现?据我了解,您总是对参数进行散列,并总是从磁盘读取结果?你不能把结果缓存在内存中吗?
标签: python memoization