Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/284.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Python中设计一个忘记(几乎只忘记)内存压力的缓存?_Python_Caching - Fatal编程技术网

如何在Python中设计一个忘记(几乎只忘记)内存压力的缓存?

如何在Python中设计一个忘记(几乎只忘记)内存压力的缓存?,python,caching,Python,Caching,假设我有一个Python中的URL类。URL类表示URL并提供下载其内容的方法。它还缓存该内容以加速后续调用 @dataclass(frozen) class URL: url: str _cache: Optional[bytes] = None def get_content(self) -> bytes: if self._cache is None: self._cache = requests.get(self.u

假设我有一个Python中的URL类。URL类表示URL并提供下载其内容的方法。它还缓存该内容以加速后续调用

@dataclass(frozen)
class URL:
    url: str
    _cache: Optional[bytes] = None

    def get_content(self) -> bytes:
        if self._cache is None:
            self._cache = requests.get(self.url)
        return self._cache
到目前为止,该代码运行良好。现在我被要求在这里下载大量的URL(出于理智的原因)。为了防止误用的可能性,我想支持这样的用例,即
URL
的每个实例都将处于活动状态,直到所有URL都被下载

大量的
URL
处于活动状态并被缓存会导致内存耗尽。现在我想知道如何设计一个只有在内存压力下才会忘记的缓存

我考虑了以下备选方案:

  • 弱值字典将在删除最后一个强引用后立即忘记。这在这里没有帮助,因为它会导致出现当前情况或禁用缓存
  • LRUCache需要事先确定容量。然而,我需要的缓存只有在缓存尽可能多的元素时才有用。缓存100还是100.000中的1000并不重要
tl;dr:我如何在Python中实现一个缓存,该缓存保存弱引用,并且只在内存压力下少量删除它们

更新:

我心里没有明确的标准。我希望其他人已经开发出我不知道的好的解决方案。在Java中,我认为这是一个可以接受的解决方案

MisterMyagi找到了一个很好的措辞:

如果某个不相关的数值计算需要内存,那么URL缓存将逐出一个项

我希望尽可能长地保留元素,但在同一python进程的任何其他代码需要时释放它们


也许一个解决方案将只由垃圾收集器删除URL实例。然后我可以尝试相应地配置垃圾收集器。但是也许有人已经想出了一个更聪明的主意,所以我可以避免重新发明轮子。

我为我所面临的具体问题找到了一个很好的解决方案。不幸的是, 这不是一个具体问题的解决办法,这个问题只涉及一个问题 隐藏物因此,我不会接受我的答案。然而,我希望这将是鼓舞人心的 对其他人来说

在我的应用程序中,有一个存储后端将调用
url.get\u content()
。使用存储后端大致如下所示:

storage = ConcreteStorageBackend()
list_of_urls = [URL(url_str) for url_str in list_of_url_strings]
for url in list_of_urls:
    storage.add_url(url)
storage.sync()  # will trigger an internal loop that calls get_content() on all URLs.
很容易看出,当
list\u\u URL
是巨大的缓存
get\u content()
可能会导致内存问题。这里的解决方案是,替换(或操纵) URL对象,以便新的URL对象从存储中检索数据 后端

  • 更换它们会更干净。用法可能类似于
    list\u of\u URL=storage.sync()
    其中
    storage.sync()
    返回新的URL 实例
  • 使用新函数覆盖
    URL.get_content()
    将允许用户 完全不了解这里的性能考虑
  • 在这两种情况下,缓存都意味着避免反复下载内容 而是从存储后端获取它。为此,从 存储后端必须比再次下载内容快,但我 假设这种情况经常发生

    通过存储后端进行缓存在许多方面带来了另一个很酷的好处 案例:操作系统内核本身负责缓存。我想大部分的存储 后端最终将写入磁盘,例如文件或数据库。在 Linux内核至少在空闲RAM中缓存磁盘IO。因此,只要你的公羊是 如果足够大,您将以 内存但是,缓存不会阻止其他更重要的内存分配, e、 g.一条评论中提到的一些不相关的数值计算

    我再次意识到,这与上述问题并不完全相符,因为 依赖于存储后端,并且不会后退以从中下载数据
    再次上网。我希望这个答案对其他人有所帮助。

    你对“记忆压力”的标准是什么?缓存占用了x%的应用程序内存,或x%的机器内存,或分配内存失败?我还没有一个标准。我希望有一个明智的选择,通过一个迄今为止我还没有找到的解决方案来实现。我希望任何解决方案至少都能防止内存错误。防止在缓存之外没有所有者的情况下释放对象可能是一个好的开始。“防止在缓存之外没有所有者的情况下释放对象”只意味着将weakref容器替换为常规容器–例如,将
    WeakValueDictionary
    替换为
    dict
    。在构建基于内存的缓存时,您正在努力解决哪些方面的问题?原则上,您知道如何为任何策略构建缓存吗?我相信我可以实现LRU或LFU缓存。使用
    dict
    将导致禁用缓存行为。试图在基于
    dict
    的自定义缓存中捕获
    MemoryError
    是不够的,因为我不能保证
    MemoryError
    将发生在缓存中。我不太明白:您所说的“使用
    dict
    将导致禁用缓存行为”是什么意思?具有显式策略的缓存确实使用强引用容器,以便显式管理生存期。例如,
    functools.lru\u cache
    使用自定义的
    orderedict
    实现。至于保证错误发生的位置,如果任何其他代码需要内存,是否希望缓存释放一个项?如果某个不相关的数值计算需要内存,那么URL缓存将逐出一个项?