只加载一次经过pickle处理的列表 - Django\Python
我有一个pickle文件,里面存着一些编译好的正则表达式和其他数据。
加载这个文件大约需要1到1.5秒。
有没有好的方法可以在我的视图中使用这个列表,但只让pickle处理这个文件一次呢?
编辑:
把它导入到settings.py里算不算可以呢?
有什么想法吗?
3 个回答
你可以先把它加载进来,然后使用Django的缓存框架来存储,这样它就只会被加载一次。
我会写一个Python模块,里面有一个单例类,这个类有一个初始化的方法,用来把存储的数据读取成Python对象。然后你可以根据需要写一些“获取”方法,来提取信息。
接着在你的settings.py文件里,只需要调用这个初始化的方法。任何需要从这个模块获取信息的地方,只要导入这个模块,然后使用获取方法就可以了。
怎么做
首先,创建一个叫做 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()
。
为什么你可能不想这样做
- 如果你的网站每个页面都要加载一些生成需要 2 秒的内容,那就有问题了。你可能需要重新考虑你的架构。
- 如果数据不是用来返回值,而是要在用户操作后运行某个过程,那么使用异步函数可能更好,可以使用像 Celery 这样的工具。
re
模块本身就会缓存正则表达式,所以你可能不需要再编译它们了。其他数据可能可以用基本类型表示。把它们都存储为字符串和其他基本类型,放在像 memcached 或 redis 这样的缓存后端中,这样会更干净。而且,如果一个 Python 进程更新了缓存,其他进程会知道这个变化。上面的代码片段就做不到这一点。
关于 settings.py 的最后一点
你不应该把它放在 settings.py 文件中:
- 如果你硬编码它,你的设置文件会变得难以阅读,而且在使用版本控制工具时会很麻烦。
- 你不能在这里动态放置,因为在 Django 中设置模块是只读的,除非你使用一些丑陋的黑客手段,这可能会导致意想不到的问题。