只加载一次经过pickle处理的列表 - Django\Python

3 投票
3 回答
2041 浏览
提问于 2025-04-16 11:26

我有一个pickle文件,里面存着一些编译好的正则表达式和其他数据。

加载这个文件大约需要1到1.5秒。

有没有好的方法可以在我的视图中使用这个列表,但只让pickle处理这个文件一次呢?

编辑:

把它导入到settings.py里算不算可以呢?


有什么想法吗?

3 个回答

1

你可以先把它加载进来,然后使用Django的缓存框架来存储,这样它就只会被加载一次。

http://docs.djangoproject.com/en/dev/topics/cache/

2

我会写一个Python模块,里面有一个单例类,这个类有一个初始化的方法,用来把存储的数据读取成Python对象。然后你可以根据需要写一些“获取”方法,来提取信息。

接着在你的settings.py文件里,只需要调用这个初始化的方法。任何需要从这个模块获取信息的地方,只要导入这个模块,然后使用获取方法就可以了。

3

怎么做

首先,创建一个叫做 cache.py 的模块,然后:

import cache
data = getattr(cache, 'data', '') or get_my_data()

这样做会让服务器进程只加载一次数据(具体取决于你的设置、你的网络服务器以及你使用 WSGI 还是 CGI)。在开发用的网络服务器(./manage.py runserver)中,每次你修改文件时,缓存都会失效。

它是怎么工作的

在 Python 中,每个模块只会在每个 Python 进程中被导入一次。如果你多次使用 import,它只会返回已经导入的模块的引用。所以,如果你有一个 Apache 服务器在运行 mod_wsgi,并且有 4 个工作进程,get_my_data() 只会被调用 4 次,因为只有 4 个 Python 进程在运行。记住,工作进程可能会崩溃、被重启、被杀掉等等。但它应该尽量减少对 get_my_data() 的调用。

注意:如果一个进程修改了缓存数据,其他进程不会知道。 如果你的数据是静态的,这没问题。如果你需要保持数据更新,那就不行。这对这种方法或任何使用单例的方法都适用,除非你能确保只有一个 Python 进程在运行(虽然可以做到,但这不是本回答的重点)。

关于语法:

getattr(cache, 'data', '') 会返回对象 'cache' 中名为 'data' 的属性。如果不存在,就返回最后一个参数,这里是一个空字符串。

在 Python 中,or 是懒惰的,如果它能返回结果,就会停止评估其他参数。在我们的例子中,如果 'data' 是 cache 的一个属性,它在布尔上下文中会被视为 True,那么 or 会认为它已经完成了工作(因为只需要一个值为 True 就能返回 True),并且不会执行 get_my_data()。但是,如果 'data' 不是 cache 的属性,or 会评估一个空字符串,认为它是 False,然后会执行 get_my_data()

为什么你可能不想这样做

  1. 如果你的网站每个页面都要加载一些生成需要 2 秒的内容,那就有问题了。你可能需要重新考虑你的架构。
  2. 如果数据不是用来返回值,而是要在用户操作后运行某个过程,那么使用异步函数可能更好,可以使用像 Celery 这样的工具。
  3. re 模块本身就会缓存正则表达式,所以你可能不需要再编译它们了。其他数据可能可以用基本类型表示。把它们都存储为字符串和其他基本类型,放在像 memcached 或 redis 这样的缓存后端中,这样会更干净。而且,如果一个 Python 进程更新了缓存,其他进程会知道这个变化。上面的代码片段就做不到这一点。

关于 settings.py 的最后一点

你不应该把它放在 settings.py 文件中:

  • 如果你硬编码它,你的设置文件会变得难以阅读,而且在使用版本控制工具时会很麻烦。
  • 你不能在这里动态放置,因为在 Django 中设置模块是只读的,除非你使用一些丑陋的黑客手段,这可能会导致意想不到的问题。

撰写回答