我的节目正在经历令人讨厌的性能下降。它基本上是一对嵌套的for循环,它们执行一对数据集的操作,然后写入结果。问题是,在300,000对中的大约500个之后,它减慢了从.07秒/对到5秒/对,并且CPU使用率从接近100%下降到~4%。所有使用的内存都在嵌套循环之前分配,并在循环之后释放。
这是伪代码,所以你可以希望得到这个想法:
for (i=0; i<759; i++) {
read_binary_data(data_file_1, data_1);
read_binary_header(header_file_1, header_1);
for (j=i+1; j<760;j++) {
read_binary_data(data_file_2, data_2);
read_binary_header(header_file_2, header_2);
do_operation(data_1, data_2, out_data);
update_header_data(header_1, header_2, out_header);
write_binary_data_and_header(out_data, out_header);
}
}
我在第二个for循环的开头和结尾放入时序标志,看看上面引用的时间,但我想知道是否有更好的调试选项来告诉我操作速度减慢的原因。到目前为止我唯一想到的是文件系统阻塞,但我每次运行时只打开5-6个文件,每个文件在子程序结束时关闭。
下午10:15更新太平洋时间:
经过各种测试,我发现罪魁祸首似乎在read_binary_data部分。许多文件可能需要3秒钟。我将尝试将所有二进制数据打包成1个文件并一次读取所有内容,因此我只需要读取一个。我打赌我会耗尽内存,但它值得一试,如果发生这种情况,我会不那么雄心勃勃,并试图一次少于760 * 2 * 31 * 43201浮点数(我想这应该是16 GB左右?)。
答案 0 :(得分:5)
你是否正在释放你持有数据的缓冲区?听起来你已经耗尽了内存,并在500个文件后切换到交换。你的内存使用情况如何?
答案 1 :(得分:3)
也许你的文件写作效率低下,随着你的进步,你需要做更多的搜索?
也许注释掉写入磁盘的两行,看看你是否得到了一致的运行。
否则,它可能是你的读物。很难看出你是如何实际完成文件操作的,但很容易以非常昂贵的方式完成它。
无论哪种方式,如果你的CPU很低而你的内存很低,你就会有阻塞的I / O操作!
答案 2 :(得分:2)
尽管您声称内存未在循环内部分配,但首先想到的是
如果没有更多关于实际情况的详细信息,例如您正在运行的环境或您的功能正在调用的其他功能,则无法推测更多。这个问题太抽象了。
答案 3 :(得分:2)
首先回答您的实际问题 - “C”没有与I / O性能或任何其他类型性能相关的调试选项。您的IDE,调试器或操作系统可能,但我担心我不知道任何细节。
愚蠢的问题 - 所有循环都产生相同数量的输出吗?也许前500个很小。
可能是500个循环是填充磁盘写入缓存所需的时间(在一个或多个级别 - 进程,操作系统,硬件),之后程序受I / O限制。在不知道所涉及的数据量的情况下,无法确切地说这是否可能。
尝试将1GB数据写入文件,然后计算时间,以便大致了解持续率是多少。如果每对0.07秒,每对数据量乘以比该速率更快的速度,那么您的初始快速速率是一次性特价:磁盘迟早要赶上。
除此之外,请多考虑一下您的输出实际正在做什么,而不是详细说明。写一条直线?来回寻求?将记录插入到磁盘上的有序数组中,以便每次写入必须平均移动50%的数据到目前为止?随着时间的推移,不同的访问模式显然具有非常不同的预期性能。
我专注于输出而不是输入,假设读取缓存是无用的,因此您的读取速度将始终相当一致。情况不一定如此,但如果计算机无法预测您的访问模式,那么这是一个相当不错的近似值。
即便如此,300000 * 5秒超过400小时。这足以让任何凡人计算机多次写入整个硬盘。因此,你必须做一些非常奇怪的事情,因为原始写入速度可以满足它。
答案 4 :(得分:0)
除非你分配了太多内存以致系统开始交换,否则你就是I / O绑定。
答案 5 :(得分:0)
你正在进行线性搜索。您的数据是否存储在文件中?
如果是,则您可以一次只读取所有数据,然后将其存储在二进制搜索树中。它将减少程序的时间复杂度。