什么可以导致程序第二次运行得更快?

Mas*_*ler 29 windows delphi performance caching

我在编写测试代码时注意到的一点是,长时间运行的操作在程序运行第一次运行时比在后续运行时运行的时间长得多,有时甚至会超过10倍.显然这里有一些冷缓存/暖缓存问题,但我似乎无法弄清楚它是什么.

它不是CPU缓存,因为这些长时间运行的操作往往是我提供大量数据的循环,并且它们应该在第一次迭代后完全加载.(另外,卸载和重新加载程序应该清除缓存.)

此外,它不是光盘缓存.我已经通过预先从光盘加载所有数据并在之后处理它来排除这种情况,而实际的CPU绑定数据处理正在缓慢进行.

那么什么可能导致我的程序在第一次运行时运行缓慢,但是如果我关闭它并再次运行它,它运行得更快?我已经在几个不同的程序中看到了这些,这些程序做了很多不同的事情,所以它似乎是一个普遍的问题.

编辑:为了澄清,我在Delphi写作,虽然我不认为这是特定于Delphi的问题.但这意味着无论问题是什么,它都与JIT问题,垃圾收集问题或托管代码带来的任何其他包袱无关.我不是在处理网络连接.这是纯CPU绑定处理.

一个例子:脚本编译器.它运行如下:

  • 从光盘将整个文件加载到内存中
  • 将整个文件放入令牌队列中
  • 将队列解析为树
  • 在树上运行codegen以生成字节码

如果我将光盘中的所有内容从光盘加载到内存后将一个巨大的脚本文件(~100k行)提供给它,则lex步骤在我第一次运行时大约需要15秒,在后续运行时大约需要2秒.(是的,我知道这还有很长一段时间.我正在努力......)我想知道这种减速的来源以及我能做些什么.

Eri*_*nge 13

要尝试三件事:

  • 在采样分析器中运行它,包括"冷"运行(重启后的第一件事).通常应该足够了.
  • 检查内存使用情况,它是否会变得如此之高(甚至是短暂的)操作系统必须从RAM中交换内容以为您的应用腾出空间?仅这一点就可以解释你所看到的.另请查看启动应用时的可用内存量.
  • 启用系统性能工具并检查I/O计数器或文件访问,并确保在FileMon/Process Explorer下您没有忘记的某些文件或网络访问(剩余日志/测试代码)


Ste*_*314 5

即使(特别是)对于非常小的命令行程序,问题可能是加载进程所需的时间,链接到动态链接的库等.我相信现代操作系统如果相同的程序是相同的,则避免重复大量的这项工作.一次运行两次,或反复运行.

我也不会轻易地忽略CPU缓存.0级缓存与内部循环非常相关,但对于同一应用程序的第二次运行则更少.在我便宜的Athlon 2 X4 645系统上,每个核心有64K + 64K(数据+指令)0级缓存 - 并不是一个巨大的内存量.1级缓存是每个核心IIRC 512K,因此不太可能因为启动程序的新运行所需的O/S代码,调用操作系统服务和标准库等而无法完成无关紧要.2级缓存(在拥有它的CPU上 - 我的Athlon 2没有,IIRC)仍然更大,并且主板/芯片组可能会提供更高级别和更大的缓存.

至少还有一种其他类型的缓存 - 分支预测表.虽然我认为他们会比0级缓存更快地变得无关紧要.

我通常发现单元测试程序第一次运行速度慢很多倍.但是,程序越大越复杂,效果就越不显着.

一段时间以来,应用程序的性能通常被认为是不确定的.虽然不是严格来说,但性能是由许多难以预测的因素决定的,因此它是一个很好的模型.例如,如果CPU有点温暖,可以降低时钟速度以防止过热.并且温度在芯片的不同部分变化,并且以复杂的方式在芯片上传导变化.随着时钟速度的变化和不同代码片段的不同需求改变温度变化的模式,混沌(如混沌理论)行为有明显的可能性.

在某些平台上,如果程序的第一次运行得到处理器运行,如果它是"快速"(而不是冷却/安静)模式,我不会感到惊讶,这意味着第二次运行的开始受益于该速度提升以及结束.但是,这将是一个棘手的问题 - 它必须是一个CPU密集型程序,如果你的冷却不充分,处理器可能会再次减速以避免过热.

  • IMHO CPU缓存和分支预测/流水线处理在这里不相关,因为代码总是相同的. (2认同)

TMN*_*TMN 5

我想这就是您所有的库/ DLL。这些通常是在运行时按需加载的,因此,程序首次运行时,操作系统必须从磁盘读取所有内容。但是,一旦读取,它们将保持加载状态,除非您的系统开始运行的内存不足。因此,如果您连续运行几次相同的程序,则第一次运行会耗费大量的加载时间,而其他运行会受益于预加载的库。


Mus*_*sis 1

有很多事情都可能导致这种情况。举一个例子:如果您在ADO.NET打开连接池(这是默认设置)的情况下用于数据访问,那么您的应用程序第一次运行时将受到创建数据库连接的影响。当您的应用程序关闭时,连接将通过 保持在打开状态ADO.NET,因此下次您的应用程序运行并进行数据访问时,它将不必承受实例化连接的影响,因此会显得更快。