2

我正在使用 python 来设置计算密集型模拟,然后在自定义构建的 C 扩展中运行它,最后在 python 中处理结果。在模拟过程中,我想在每个时间步存储一个固定长度的浮点数(C 双精度转换为 PyFloatObjects)代表我的变量,但我不知道提前多少时间步。模拟完成后,我需要以一种形式将结果传递回 python,其中为每个单独变量记录的数据可作为类似列表的对象(例如,(围绕 a)连续数组的(包装器)连续数组,分段连续具有固定步幅的矩阵中的数组或列)。

目前,我正在创建一个字典,将每个变量的名称映射到包含 PyFloatObject 对象的列表。这种格式非常适合在后期处理阶段使用,但我觉得创作阶段可能会快很多。

时间非常关键,因为模拟已经是一项计算量很大的任务。我希望 A. 购买大量内存和 B. 明智地设置您的实验的组合将使整个日志适合 RAM。但是,使用我当前的 dict-of-lists 解决方案将每个变量的日志保存在内存的连续部分中将需要大量的复制和开销。

我的问题是:什么是一种聪明的、低级的方法,可以以最小的空间/时间开销在内存中快速记录千兆字节的双精度,并且仍然可以转换为简洁的 python 数据结构?


澄清:当我说“记录”时,我的意思是存储到模拟之后。一旦完成,后处理阶段就开始了,在大多数情况下,我只会存储结果图。所以我实际上不需要将数字存储在磁盘上。


更新:最后,我稍微改变了我的方法,并将日志(作为将变量名映射到序列类型的字典)添加到函数参数中。这允许您传入对象,例如列表或 array.arrays 或任何具有 append 方法的对象。这会增加一点时间开销,因为我使用 PyObject_CallMethodObjArgs 函数来调用 Append 方法而不是 PyList_Append 或类似方法。使用数组可以减少内存负载,这似乎是我能做的最好的事情,而不是编写自己的扩展存储类型。谢谢大家!

4

2 回答 2

2

您可能需要考虑在 Cython 中执行此操作,而不是作为 C 扩展模块。Cython 很聪明,可以让你以非常 Python 的方式做事,即使它同时允许你使用 C 数据类型和 python 数据类型。

你检查过阵列模块吗?它允许您在单个集合中存储大量标量、同类类型。

如果您真正“记录”这些内容,而不仅仅是将它们返回给 CPython,您可能会尝试打开一个文件并 fprintf'ing 它们。

顺便说一句,realloc 可能是您的朋友,无论您使用 C 扩展模块还是 Cython。

于 2012-08-16T20:42:31.907 回答
1

这将更多是大量的想法,而不是一致的答案,因为听起来这就是您要寻找的。如果没有,我道歉。

您在这里要避免的主要事情是将数十亿的 PyFloatObjects 存储在内存中。有几种方法可以解决这个问题,但它们都围绕着存储数十亿个普通的 C 双精度对象,并找到某种方法将它们暴露给 Python,就好像它们是 PyFloatObjects 的序列一样。

要让 Python(或其他人的模块)完成这项工作,您可以使用 numpy 数组、标准库数组、结构模块顶部的简单手工包装器或 ctypes。(使用 ctypes 来处理扩展模块有点奇怪,但没有什么能阻止你这样做。)如果你使用的是 struct 或 ctypes,你甚至可以通过创建一个巨大的文件来超越你的内存限制和根据需要将窗口映射到其中。

为了让你的 C 模块完成这项工作,而不是实际返回一个列表,而是返回一个满足序列协议的自定义对象,所以当有人调用时,比如 foo. getitem (i) 您将 _array[i] 动态转换为 PyFloatObject。

mmap 的另一个优点是,如果您正在迭代地创建数组,您可以通过流式传输到文件来创建它们,然后通过将结果文件作为内存块映射回来使用它们。

否则,您需要处理分配。如果您使用的是标准数组,它会根据需要进行自动扩展,否则,您将自己进行。如果需要,进行重新分配和复制的代码并不难,网上有很多示例代码,但你必须编写它。或者您可能想要考虑构建一个跨步容器,您可以将其暴露给 Python,就好像它是连续的一样,即使它不是。(你可以通过复杂的缓冲区协议直接做到这一点,但我个人一直觉得这比编写自己的序列实现更难。)如果你可以使用 C++,vector 是一个自动扩展数组,而 deque 是一个跨步容器(如果你有 SGI STL 绳索,对于你正在做的事情,它可能是一个更好的跨步容器)。

正如另一个答案指出的那样,Cython 可以帮助解决其中的一些问题。对于“将大量浮点数暴露给 Python”部分来说,并没有那么多;您可以将 Python 部分的部分移动到 Cython 中,在那里它们将被编译成 C。如果幸运的话,所有需要处理大量浮点数的代码都将在 Cython 实现的 Python 子集中工作,并且您需要向实际解释代码公开的唯一内容是更高级别的驱动程序(即使是这样)。

于 2012-08-16T21:42:11.807 回答