如何腌制“记忆化”的 Python 函数?
Posted
技术标签:
【中文标题】如何腌制“记忆化”的 Python 函数?【英文标题】:How do I pickle a "memoized" Python function? 【发布时间】:2021-02-14 09:51:16 【问题描述】:我有以下代码:
def f(input,MEM=):
if len(MEM) == 0:
with open('dill.pkl', 'rb') as f:
MEM = dill.load(f)
if input not in MEM:
intended_output = complex_function(input)
MEM[input] = intended_output
return MEM[input]
运行大量输入时,我发现我的代码运行速度比我最初没有加载 MEM
时要慢得多。即,与
def f(input,MEM=):
if len(MEM) == -1:
return None
if input not in MEM:
intended_output = complex_function(input)
MEM[input] = intended_output
return MEM[input]
我同时运行f
和f2
来处理四千个输入,f
需要半小时才能完成,但 f2
只需 40 秒即可完成。这是因为当我用莳萝加载MEM
时,它由访问速度较慢的结构表示?我尝试过复制和深度复制 MEM,这只会使问题变得更糟(尤其是深度复制,即使是较小的输入也需要几秒钟的时间)。
【问题讨论】:
不确定是否与问题有关,但(1)如果使用with open(...)
,则不需要f.close()
; (2) 你根本没有使用f
!?
糟糕,我是想写MEM = dump(f)
。我不知道f.close()
是不必要的,我现在也更改了。
不幸的是,这并没有明显改变我的代码速度。
如果您想添加自己的答案,请将其添加为答案,而不是将其编辑到问题中。
我是dill
作者。您可能想查看klepto
如何使用dill
。 klepto
是一个缓存库,它利用 dill
来帮助进行记忆..
【参考方案1】:
MEM = dill.load(...)
这会创建一个名为 MEM
的新局部变量,但不会更改默认参数 MEM
。
因此,默认参数MEM
是一个空字典,并且每次调用该函数时都会取消文件。
要实际更改默认参数,您可以简单地使用:
MEM.update(dill.load(...))
见https://docs.python.org/3/library/stdtypes.html#dict.update。
【讨论】:
【参考方案2】:最好只取消腌制一次或尽可能少。
在许多情况下运行该函数时,最好避免循环并改用诸如利用 C 代码的 .apply 之类的函数。
也许您可以并行化,因此您可以使用所有内核来完成任务。也许这有帮助:https://***.com/a/66079049/7127519
【讨论】:
我知道 for 循环不是主要问题。我在f2
中包含了虚拟循环,它运行得非常快。关于(1),我如何只取消腌制一次?我对莳萝很陌生。
也许您可以在函数外部和开头取消选择。
我的意思是,第一个 if 语句只会为真一次。因此,我认为这没有用...哦,除非这可能导致 MEM
在每次调用后都无法保存!以上是关于如何腌制“记忆化”的 Python 函数?的主要内容,如果未能解决你的问题,请参考以下文章