反复附加到大型列表(Python 2.6.6)

时间:2011-04-29 15:17:16

标签: python list performance append

我有一个项目,我从微控制器通过串口读取ASCII值(如下所示:AA FF BA 11 43 CF等) 输入快速进入(38个字符集/秒)。 我正在接受此输入并将其附加到所有测量的运行列表中。

大约5个小时后,我的名单已增加到约855000个条目。

我了解到列表越大,列表操作就越慢。我的目的是让这个测试运行24小时,这应该会产生大约3M的结果。

是否有一种更有效,更快捷的方式附加到列表然后list.append()?

谢谢大家。

5 个答案:

答案 0 :(得分:32)

  

我了解到列表越大,列表操作就越慢。

总的来说这不是真的。尽管名称不同,但Python中的列表不是链接列表而是数组。阵列上有O(n)的操作(例如,复制和搜索),但您似乎不使用任何这些操作。根据经验:如果它被广泛使用和惯用,一些聪明的人去选择一种聪明的方法来做到这一点。 list.append是一种广泛使用的内置函数(底层C函数也用于其他地方,例如列表推导)。如果有更快的方法,它就已经在使用中了。

正如您在检查the source code时所看到的那样,列表是过度分配的,即当它们被调整大小时,它们为一个项目分配的内容超过了需要,因此可以追加下一个n项而无需另外调整大小(这是上))。增长不是恒定的,它与列表大小成正比,因此随着列表变大,调整大小变得越来越少。以下是来自listobject.c:list_resize的片段,用于确定位置:

/* This over-allocates proportional to the list size, making room
 * for additional growth.  The over-allocation is mild, but is
 * enough to give linear-time amortized behavior over a long
 * sequence of appends() in the presence of a poorly-performing
 * system realloc().
 * The growth pattern is:  0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
 */
new_allocated = (newsize >> 3) + (newsize < 9 ? 3 : 6);

Mark Ransom指出,较旧的Python版本(&lt; 2.7,3.0)有一个错误,使GC破坏了这一点。如果您有这样的Python版本,则可能需要禁用gc。如果你不能,因为你产生了太多垃圾(这会导致引用计数),你就会失去运气。

答案 1 :(得分:12)

您可能需要考虑的一件事是将数据写入收集的文件中。我不知道(或非常关心)它是否会影响性能,但它有助于确保在电源闪烁时不会丢失所有数据。获得所有数据后,您可以将其从文件中取出并将其插入列表或数组或numpy矩阵或其他任何处理中。

答案 2 :(得分:2)

追加到python列表的成本不变。它不受列表中项目数量的影响(理论上)。实际上,一旦内存不足并且系统开始交换,附加到列表的速度会变慢。

http://wiki.python.org/moin/TimeComplexity

理解你为什么要将东西附加到列表中会很有帮助。您打算如何处理这些物品。如果您不需要所有这些,您可以构建一个环形缓冲区,如果您不需要进行计算,则可以将列表写入文件等。

答案 3 :(得分:0)

首先,每秒38个双字符集,1个停止位,8个数据位和无奇偶校验,只有760波特,完全不快。

但无论如何,我的建议是,如果你担心有过大的列表/不想使用一个巨大的列表,只要在磁盘上存储一个列表,一旦达到一定的大小并开始一个新的列表,重复直到你获得所有数据,然后在你收到数据后将所有列表合并为一个。

虽然你可以完全跳过这些子列表,只是按照nmichaels的建议,将数据写入文件并使用一个小的循环缓冲区来保存尚未写入的接收数据。

答案 4 :(得分:0)

如果知道数组的长度,使用numpy可能会更快,你可以将十六进制代码转换为整数:

import numpy
a = numpy.zeros(3000000, numpy.int32)
for i in range(3000000):
   a[i] = int(scanHexFromSerial(),16)

这将为您提供一个整数数组(您可以使用hex()将其转换回十六进制),但根据您的应用程序,这可能也适用于您。