这是关于previous one的后续问题。
考虑一下这个代码,它比previous question中的代码少一些(但仍然比我真实的简单得多)
import sys
data=[]
for line in open(sys.argv[1]):
data.append(line[-1])
print data[-1]
现在,我期待更长的运行时间(我的基准文件长度为65150224行),可能要长得多。情况并非如此,它在与之前相同的hw中运行约2分钟!
data.append()非常轻量级吗?我不相信,因此我写了这个假代码来测试它:
data=[]
counter=0
string="a\n"
for counter in xrange(65150224):
data.append(string[-1])
print data[-1]
这在1.5到3分钟内运行(运行之间存在很大的差异)
为什么我不能在前一个程序中获得3.5到5分钟?显然,data.append()与IO并行发生。
这是个好消息!
但它是如何运作的?它是一个记录的功能吗?我的代码是否有任何要求我应该遵循以使其尽可能地工作(除了负载平衡IO和内存/ CPU活动)?或者只是简单的缓冲/缓存?
再一次,我将这个问题标记为“linux”,因为我只对linux特定的答案感兴趣。如果您认为值得这样做,请随意提供与操作系统无关的内容,甚至是其他操作系统的答案。
答案 0 :(得分:8)
显然,data.append()与IO并行发生。
我不敢。 可以在Python中并行化IO和计算,但它不会神奇地发生。
您可以做的一件事是使用posix_fadvise(2)
向操作系统提示您计划按顺序读取文件(POSIX_FADV_SEQUENTIAL
)。
在600 meg文件(ISO)上执行“wc -l”的一些粗略测试中,性能提高了约20%。清除磁盘缓存后立即完成每项测试。
对于fadvise的Python界面,请参阅python-fadvise。
答案 1 :(得分:1)
文件中的行数有多大?如果它们不是很长(任何低于1K的东西可能都符合条件),那么由于输入缓冲,你可能会看到性能提升。
答案 2 :(得分:1)
为什么你认为list.append()是一个较慢的操作?它非常快,考虑到列表用来保存对其中对象的引用的内部指针数组在越来越大的块中分配,因此每个附加实际上不会重新分配数组,并且大多数可以简单地增加长度计数器和设置指针和增量。
答案 3 :(得分:1)
我没有看到任何证据表明“data.append()与IO并行发生。”像Benji一样,我认为这不像你想象的那样是自动的。您表明,执行data.append(line [-1])所花费的时间与lc = lc + 1大致相同(与IO和行拆分相比,基本上没有时间)。 data.append(line [-1])非常快,这并不奇怪。人们会期望整行都在快速缓存中,并且如前所述,append会提前准备缓冲区,并且很少需要重新分配。此外,line [-1]将始终为'\ n',除了可能是文件的最后一行(不知道Python是否为此优化)。
我有点惊讶的唯一部分是xrange是如此可变。我希望它总是更快,因为没有IO,而你实际上并没有使用计数器。
答案 4 :(得分:1)
如果您的运行时间因第二个示例的运行时间而异,我怀疑您的计时方法或外部影响(其他进程/系统负载)会将时间偏移到不给出任何时间的程度可靠的信息。