【问题标题】:Storing large python object in RAM for later use将大型 python 对象存储在 RAM 中以备后用
【发布时间】:2012-12-16 23:50:46
【问题描述】:

是否可以将 python(或 C++)数据存储在 RAM 中以备后用?如何实现?

背景: 我编写了一个程序来查找输入表中的哪些行与给定的正则表达式匹配。我可以在大约一秒或更短的时间内找到所有的行。然而问题是我每次启动这个程序时都会将输入表处理成一个 python 对象。此过程大约需要 30 分钟。

该程序最终将在 RAM 超过 128GB 的​​机器上运行。 python 对象需要大约 2GB 的 RAM。输入表很少更改,因此 python 对象(我目前每次都在重新计算)实际上很少更改。有没有一种方法可以让我创建这个 python 对象一次,将其存储在 RAM 24/7 中(如果输入表更改或服务器重新启动,则重新创建),然后每次需要时都使用它?

注意:python 对象在创建后不会被修改。但是,如果需要,我需要能够重新创建此对象。

编辑:我能想到的唯一解决方案就是让程序 24/7 全天候运行(作为守护进程??),然后根据需要向它发出命令。

【问题讨论】:

  • 你正在生成一个你宁愿存储的位图索引,而不是每次 Python 加载时计算 - 我们是这样吗?
  • 最简单的做法是让您的管理员为您制作一个 RAM 磁盘并将结果作为 pickle 文件写入其中。如果这是不可能的,你需要做一些体操:)
  • redis.io 也可能是一个可行的选择
  • @ Jon Clements - 是的,就是这样。我正在考虑编写一个在启动/重新启动时处理输入表的守护程序。但是我不确定我将如何向这个守护进程发出命令。但我不确定这是否是要走的路,可能还有更好的方法?

标签: c++ python memory ram


【解决方案1】:

要在 RAM 中存储任何内容,您需要一个正在运行的进程。因此,最简单的解决方案是实现您在编辑中编写的内容。您还可以创建一个始终运行的新进程,并让旧进程连接到新进程以获取数据。如何连接取决于您。您可以使用共享内存或 TCP/IP 套接字。 TCP/IP 的优点是允许数据可通过网络访问,但请确保其安全。

--编辑--

大多数操作系统还允许您安装一定速度的 RAM 作为驱动器。一个RAM drive。你可以写(像尼尔建议的那样)对象。

【讨论】:

  • 这是我建议的解决方案。
  • 我将查看 RAM 驱动器。乍一看,这似乎是我想要的。
  • 最后我决定使用一个 24/7 运行的守护进程,从而将数据保存在内存中。
【解决方案2】:

您可以尝试腌制您的对象并将其保存到文件中,这样每次程序运行时它只需反序列化对象而不是重新计算它。希望服务器的磁盘缓存在必要时保持文件热。

【讨论】:

  • 是的,这将是一种方法。但是,每次运行时反序列化仍然需要一些时间。如果这些数据已经存在于 RAM 中,则不会花费时间(在我的情况下这不是问题,问题是我不知道如何)。
【解决方案3】:

我们定期加载和存储比 2 Gb 大得多的内存块,时间(秒)。我们可以从使用 3 年的 SAN 获得 350 Mb/s。

瓶颈/开销似乎主要涉及 python 对象管理。我发现使用 marshal 比 cPickle 快得多。结合使用涉及最少 python 对象句柄的数据结构,这已经足够快了。

对于数据结构,您可以使用array.arraynumpyarray.array 更便携(不涉及额外的库),但numpy 在很多方面都更方便。 例如,您将创建一个包含 1000 万个元素的 array.array('i'),而不是 1000 万个整数(python 对象)。

使用 marshal 最好的部分是它是一种非常简单的格式,您可以使用 c/c++ 代码轻松地写入和读取。

【讨论】:

    【解决方案4】:

    您的问题描述有点模糊,可以通过多种不同方式阅读。

    我读到这篇文章的一种方式是,您在磁盘上有某种数据结构的 ASCII 表示。你将这个表示读入内存,然后用 grep 一次或多次查找与给定正则表达式匹配的内容。

    加快速度很大程度上取决于相关数据结构。

    如果您只是简单地进行行拆分,那么也许您应该使用单个读取指令将整个内容读入一个字节数组。然后,您可以更改 grep 的方式以使用不跨越多行的字节数组 grep。如果您通过将^.*? 放在开头并将.*?$ 放在末尾来调整表达式以始终匹配整行(? 强制最小而不是最大咀嚼),那么您可以检查匹配表达式的大小以找出要转发的字节数。

    或者,您可以尝试使用mmap 模块来实现类似的功能,而无需读取任何内容并产生复制开销。

    如果要进行大量处理来创建您的数据结构,并且您想不出一种方法以非常原始的方式将文件中的数据用作简单的字节数组,那么您就剩下各种其他解决方案取决于,尽管其中听起来创建一个守护进程是最好的选择。

    由于您的基本操作似乎是“告诉我哪些表条目与正则表达式匹配”,因此您可以使用 xmlrpc.serverxmlrpc.client 库来简单地封装一个将正则表达式作为字符串并返回结果是任何自然的形式。该库将负责将看起来像函数调用的内容通过套接字或其他方式封装到消息中的所有工作。

    现在,您将其实际保存在内存中的想法有点牵强附会。我认为这些天从磁盘读取 2G 的信息不需要 30 分钟。它可能最多需要 5 个,并且可能少于 1 个。因此,您可能想看看您是如何构建数据结构的,看看是否可以对其进行优化。

    pickle 和/或 marshal 将为您购买的是高度优化的代码,用于从序列化形式构建数据结构。这将导致数据结构的创建可能会受到磁盘读取速度的限制。这意味着您要解决的真正问题不是每次都从磁盘读取它,而是在您自己的地址空间中构建数据结构。

    将它保存在内存中并使用守护程序并不能保证它会保留在内存中。它只是保证它在 Python 进程的地址空间中保持为您想要的数据结构。操作系统可能随时决定将该内存交换到磁盘。

    同样,这意味着关注从磁盘读取它的时间可能不是正确的关注点。相反,请关注如何在 Python 进程的地址空间中有效地重新创建(或保留)数据结构。

    无论如何,这就是我在这个话题上的啰嗦。鉴于你的问题含糊不清,没有明确的答案,所以我只是给出了一些可能的技术和一些指导思想的大杂烩。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-02-24
      • 1970-01-01
      • 2017-12-05
      • 1970-01-01
      • 2011-10-21
      • 2013-08-03
      • 2011-04-28
      • 1970-01-01
      相关资源
      最近更新 更多