当我的 django 应用程序尝试从缓存中获取或存储某些内容时,我有时会收到以下错误:
c = cache.get(pk)
File "/opt/python3/lib/python3.4/site-packages/django/core/cache/__init__.py", line 131, in __getattr__
return getattr(caches[DEFAULT_CACHE_ALIAS], name)
File "/opt/python3/lib/python3.4/site-packages/django/core/cache/__init__.py", line 113, in __getitem__
cache = _create_cache(alias)
File "/opt/python3/lib/python3.4/site-packages/django/core/cache/__init__.py", line 88, in _create_cache
return backend_cls(location, params)
File "/opt/python3/lib/python3.4/site-packages/django/core/cache/backends/memcached.py", line 185, in __init__
value_not_found_exception=pylibmc.NotFound)
AttributeError: 'module' object has no attribute 'NotFound'
但是为什么呢? 该模块具有该属性,并且大多数时候它都可以工作,没有同名的文件可以破坏它,在哪里寻找原因?
>>> import pylibmc
>>> pylibmc.NotFound
<class '_pylibmc.NotFound'>
>>>
tl;dr:尝试在应用程序启动位置(如uwsgi
或manage.py
文件)导入 pylibmc。
我的猜测是,在PyLibMCCache.__init__
内部的请求线程中导入pylibmc
而不是在应用程序启动时,这是一个多线程问题。(IMO Django 在那里进行导入,因为并非所有 Django 安装都使用 pylibmc
,因此他们不应该将其作为依赖项强加在每个应用程序上)
虽然我对import
工作原理的内部结构不够熟悉,但我怀疑发生的事情如下所示
- 线程 #1 尝试导入
pylibmc
- 线程 #1 在
sys.modules
中放置一个占位符,以便pylibmc
- 线程 #2 尝试导入
pylibmc
->
引发AttributeError
- 线程 #1 完成了
sys.modules
更新,现在pylibmc.NotFound
可用
一般来说,Python似乎不鼓励模块的运行时加载,而不是启动时加载。
强调是我的
注意:对于启动时间至关重要的项目,此类 [
importlib.util.LazyLoader
] 允许在从未使用过模块的情况下最小化加载模块的成本。对于启动时间不是必需的项目,由于加载期间创建的错误消息被推迟,因此不会脱离上下文,因此强烈建议不要使用此类。