【问题标题】:Very slow to write to Django cache写入 Django 缓存非常慢
【发布时间】:2016-05-23 19:17:44
【问题描述】:

我曾经在全局变量中缓存数据库查询以加快我的应用程序。由于这是非常不建议的(并且确实产生了问题),我想使用任何类型的 Django 缓存来代替。我尝试了 LocMemCache 和 DatabaseCache,但两者都需要...大约 15 秒 来设置我的变量(比生成数据所需的时间长两倍,大小为 7MB)。

这是预期的吗?我是不是做错了什么?

(Memcached 限制为 1MB,我无法拆分数据,其中包含任意大的二进制掩码)。

编辑:FileBasedCache 也需要 30 秒才能设置。

Settings.py:

CACHES = {
    'default': {...},
    'stats': {
        'BACKEND': 'django.core.cache.backends.db.DatabaseCache', 
        # or 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
        'LOCATION': 'stats',
    },
}

Service.py:

from django.core.cache import caches

def stats_service():
    stats_cache = caches['stats']
    if stats_cache.get('key') is None:
        stats_cache.set('key', data)  # 15s with DatabaseCache, 30s with LocMemCache
    return stats_cache.get('key')

全局变量(超快)版本:

_cache = {}

def stats_service():
    if _cache.get('key') is None:
        _cache['key'] = data
    return _cache['key']

【问题讨论】:

  • 缓存腌制这个值,我并不奇怪需要这么长时间来腌制一个 7MB 的值。根据您要缓存的内容和使用它的目的,可能会有更好的方法。
  • 这确实解释了,我完全错过了这一点。我绝对不想腌制它(显然 7MB RAM 不是问题)。我正在缓存在每次计算中重复使用的位掩码(二进制 numpy 数组)。你有什么建议吗?
  • 我发现了这个:djangosnippets.org/snippets/2396。我对全局字典的唯一担心是我在使用缓存数组的计算中使用了多处理。

标签: django caching django-cache


【解决方案1】:

一种选择可能是使用diskcache.DjangoCacheDiskCache 扩展了 Django 缓存 API 以支持按原样写入和读取二进制流(避免酸洗)。它特别适用于较大的值(例如大于 1MB 的值)。 DiskCache 是一个 Apache2 许可的磁盘和file backed cache library,用纯 Python 编写,与 Django 兼容。

在您的情况下,您可以使用 ndarray tostring 和 numpy fromstring 方法快速转换为 Python 字符串/从 Python 字符串转换。然后用io.StringIO 包装字符串以在缓存中存储/检索。例如:

from django.core.cache import cache

value = cache.get('cache-key', read=True)

if value:
    data = numpy.fromstring(value.read())
    value.close()
else:
    data = ... # Generate 7MB array.
    cachge.set('cache-key', io.StringIO(data.tostring()), read=True)

DiskCache 通过允许在磁盘上存储为二进制 blob 的类似文件的值来扩展 Django 缓存 API。 Django cache benchmarks 页面讨论和比较了替代缓存后端。

【讨论】:

  • 谢谢,我一定要试试这个。不过,我真的很想使用快速内存​​访问而不是磁盘并避免转换(
  • @muraveill 要避免使用磁盘上的文件,请增加 large_value_threshold 设置 (API docs)。缓存写入仍然存在于磁盘上,但读取将从同步的内存映射文件中发生。在这种情况下,不要用io.StringIO 包装值,只需传递原始字节字符串。他们不会被腌制。您可能还需要增加其他缓存设置以使用更多内存。
【解决方案2】:

这个 sn-p 实际上工作正常:https://djangosnippets.org/snippets/2396/

据我了解,the only problem 使用全局变量进行缓存是线程安全的,而这个 no-pickle 版本是线程安全的。

【讨论】:

    猜你喜欢
    • 2010-10-24
    • 2019-04-01
    • 2011-01-10
    • 1970-01-01
    • 1970-01-01
    • 2012-12-09
    • 1970-01-01
    • 2021-05-09
    • 2018-05-07
    相关资源
    最近更新 更多