重复添加到大列表(Python 2.6.6)

重复添加到大列表(Python 2.6.6),python,list,performance,append,Python,List,Performance,Append,我有一个项目,我通过串行端口从微控制器读取ASCII值(看起来像:AA FF BA 11 43 CF等) 输入速度很快(38个两个字符集/秒)。 我获取这个输入,并将其附加到所有度量的运行列表中 大约5个小时后,我的列表已增长到约855000条条目 我知道列表越大,列表操作就越慢。我的目的是让这个测试运行24小时,这将产生大约300万个结果 是否有一种比list.append()更有效、更快的方法附加到列表中 谢谢大家。 < P>你可能要考虑的一件事是把你的数据写到一个文件中。我不知道(或真的在

我有一个项目,我通过串行端口从微控制器读取ASCII值(看起来像:AA FF BA 11 43 CF等) 输入速度很快(38个两个字符集/秒)。 我获取这个输入,并将其附加到所有度量的运行列表中

大约5个小时后,我的列表已增长到约855000条条目

我知道列表越大,列表操作就越慢。我的目的是让这个测试运行24小时,这将产生大约300万个结果

是否有一种比list.append()更有效、更快的方法附加到列表中


谢谢大家。

< P>你可能要考虑的一件事是把你的数据写到一个文件中。我不知道(或真的在乎)它是否会影响性能,但它将有助于确保在电源中断时不会丢失所有数据。一旦获得了所有数据,您就可以将其从文件中取出,并将其放入列表、数组、numpy矩阵或其他任何处理中。

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

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

我知道列表越大,列表操作就越慢

一般来说,情况并非如此。尽管名称不同,Python中的列表不是链表,而是数组。有些操作在数组上是O(n)(例如,复制和搜索),但您似乎没有使用这些操作中的任何一个。作为经验法则:如果它被广泛使用和惯用,一些聪明的人会选择一种聪明的方式来做
list.append
是一个广泛使用的内置函数(底层C函数也用于其他地方,例如列表理解)。如果有一个更快的方法,它将已经在使用中

正如您在检查时所看到的,列表是过度分配的,也就是说,当调整列表大小时,它们为一个项目分配的数量超过了需要的数量,因此接下来的n个项目可以追加,而无需重新调整大小(即O(n))。增长不是恒定的,它与列表大小成比例,因此随着列表的增大,调整大小变得越来越少。下面是
listobject.c:list\u 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);
/*这与列表大小成比例的超额分配,腾出空间
*为了进一步的增长。这种过度分配是温和的,但也很严重
*足以在长期内产生线性时间摊销行为
*存在性能不佳的附件时的附件序列()
*系统realloc()。
*其生长模式为:0,4,8,16,25,35,46,58,72,88。。。
*/
新分配=(新闻大小>>3)+(新闻大小<9?3:6);

正如Mark Ransom所指出的,较旧的Python版本(首先,38个每秒两个字符集,1个停止位,8个数据位,并且没有奇偶校验)只有760波特,一点也不快

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


尽管您可以完全跳过子列表,只需按照nmichaels的建议,在获取数据时将数据写入文件,并使用一个小的循环缓冲区来保存尚未写入的接收数据。

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

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

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

“我知道列表越大,列表操作越慢。”
[需要引用]
您是否尝试运行了24小时,发现了问题?问题是什么?@Matt,请参阅@Mark:interest。这是一个错误,现在已经修复了。@Mark:这个问题的答案是Python GC中有一个错误,因此解决问题的方法是禁用GC,而不是使用不同的算法。列表不断增长的原因是我确实需要在稍后(捕获后)对元素进行一些数学运算,并将其作为csv文件传递(以便稍后在Matlab中进行操作)。理论上是正确的答案,但现实更复杂。除非你自己测量过,并且知道它在最近的Python版本中是固定的-请参阅,谢谢你提供的信息。我不知道这一点。+1:事实上,不向文件写入是一个非常糟糕的设计。