如何避免每次重新加载Python模块时进行计算

6 投票
13 回答
4101 浏览
提问于 2025-04-11 09:26

我有一个Python模块,它使用了一个非常大的全局字典变量。目前,我把计算代码放在模块的顶部,每次第一次导入或重新加载这个模块都需要超过一分钟,这实在是太慢了。我想知道怎么才能把计算结果保存起来,这样下次导入或重新加载的时候就不需要再计算了。我试过用cPickle,但从文件中加载这个字典变量(1.3M)所花的时间大约和计算的时间差不多。

为了更详细地说明我的问题,

FD = FreqDist(word for word in brown.words()) # this line of code takes 1 min

13 个回答

2

我猜你是把字典的内容直接粘贴到代码里了,这样可能会导致加载时变得很慢吧?我不太清楚怎么解决这个问题,不过你可以考虑在导入的时候不立即创建这个字典……可以等到第一次真正用到它的时候再去创建。

4

在第一次使用时计算你的全局变量。

class Proxy:
    @property
    def global_name(self):
        # calculate your global var here, enable cache if needed
        ...

_proxy_object = Proxy()
GLOBAL_NAME = _proxy_object.global_name

或者更好的是,通过特殊的数据对象来获取必要的数据。

class Data:
    GLOBAL_NAME = property(...)

data = Data()

举个例子:

from some_module import data

print(data.GLOBAL_NAME)

可以查看 Django 设置

17

为了澄清一下:模块内部的代码并不是每次导入模块时都会执行,而是只会执行一次。之后的导入会找到已经创建好的模块,而不是重新创建一个。你可以查看 sys.modules 来看到缓存的模块列表。

不过,如果你遇到的问题是程序运行后第一次导入所需的时间,那你可能需要用其他方法,而不是用 Python 字典。最好的办法可能是使用一种磁盘存储的形式,比如 sqlite 数据库,或者 dbm 模块中的某一个。

如果你想对接口做最小的改动,shelve 模块可能是你最好的选择——它在 dbm 模块之间提供了一个比较透明的接口,让它们表现得像一个普通的 Python 字典,可以存储任何可以被序列化的值。这里有个例子:

# Create dict with a million items:
import shelve
d = shelve.open('path/to/my_persistant_dict')
d.update(('key%d' % x, x) for x in xrange(1000000))
d.close()

然后在下一个进程中使用它。查找时应该不会有太大的延迟,因为只会对请求的键在磁盘上进行查找,所以并不需要把所有内容都加载到内存中:

>>> d = shelve.open('path/to/my_persistant_dict')
>>> print d['key99999']
99999

它比真正的字典稍慢,而且如果你做一些需要所有键的操作(比如尝试打印它),加载时间会很长,但这可能会解决你的问题。

撰写回答