我使用排序的 C 程序第一次运行速度比其他时间慢 10 倍。它使用整数文件进行排序,即使我更改数字,程序仍然运行得更快。当我重新启动 PC 时,第一次程序运行速度慢了 10 倍。我time
用来计算时间。
7 回答
即使不再需要,操作系统也会将数据保存在 RAM 中(这称为“缓存”),因此当程序再次运行时,它会从那里获取所有数据并且没有磁盘 I/O。即使您更改数据,该更改首先发生在 RAM 中,并且即使在写入文件后它也会保留在那里。
请注意,它不会永远留在 RAM 中。如果其他东西需要内存,则删除缓存。此时,需要访问磁盘(并且此时它再次缓存在 RAM 中。)
这就是为什么重启后第一次访问总是很慢的原因;由于从未从文件中读取数据,因此尚未缓存数据。
你必须做出假设并将它们面对现实。您可以合理地做出的第一件事是,它确实闻起来很像缓存问题!
问自己这些问题:
- 我的数据是否适合空闲 RAM(= 我的文件是否被 OS FS 缓存缓存?)
- 我的数据是否适合 CPU 数据缓存?
我的数据是否适合 HDD 内部缓存?
最容易丢弃的假设是 FS 缓存。在 linux 下,只需
sync; echo 3 > /proc/sys/vm/drop_caches
在每次调用程序之间发出。第一个将确保缓存的数据将进入物理介质(硬盘驱动器),第二个将从内存中删除文件系统缓存的内容。“物理介质”可能是 HDD 缓存本身,所以要小心......在 linux 下,您可以使用命令禁用此“回写”缓存
hdparm -W 0 <device>
,例如,如果您正在使用驱动器sda
,hdparm -W 0 /dev/sda
则可以完成这项工作。您可能希望在完成测试后重新启用它:)另一个假设是 CPU 缓存,看看How can I do a CPU cache flush in x86 Windows? 以及如何清除 CPU L1 和 L2 缓存
好吧,它可能是也可能不是其中之一,但尝试并没有什么坏处:)
如果您的程序进行网络访问,那么这可能是初始延迟的原因。许多网络协议需要时间来设置。一些例子:
- DNS:如果您的程序进行任何网络访问,它可能需要将主机名解析为 IP 地址。第一次它至少需要一次网络往返来填充本地缓存。以下请求会更短。
- 网络文件系统(NFS、CIFS 和其他):可以通过网络打开文件。
- 甚至一些看似无害的库函数也可能需要网络访问:主机的用户列表可以位于远程目录服务器上。
从此,您可以使用一些低级跟踪工具来查看时间花在了哪里。在 linux 上,一个基本工具是strace -r
. 其他系统可能有一些类似的工具。您的编译器还必须附带一个分析器(即gprof
用于 GCC 或可能是 Valgrind)。
我有一个非常相似的问题,但我没有加载一个大文件 - 所以我在第一次执行时间很长时感到困惑(缓存不可能是问题)。
这个答案为我指明了正确的方向——这是我的实时防病毒保护。每次我重新编译程序时,它都会重新扫描它,认为它可能是恶意的。我将我的项目路径作为“例外”添加到 Avira(就我而言)实时病毒防护。
第一次执行时的程序执行速度现在变快了!
这是因为编译器优化,它的作用是缓存结果Temoparal Locality
并保存激活记录,也节省时间,因为在链接阶段不必再次重新加载绑定对象
这不是什么新鲜事,不仅仅是你的程序很多流行的商业软件都面临这个问题。
首先查看这篇关于慢速执行的 MATLAB 文章
对于在 C# 或 Java 等虚拟机上运行的其他编程语言,这很常见。 http://en.wikipedia.org/wiki/Just-in-time_compilation#Startup_delay_and_optimizations
缓存是在 C 中发生这种情况的一个很好的理由,但 10 倍仍然是相当长的持续时间。重新启动后,您的系统也可能正在加载其他资源。
您应该在重启后 10 分钟后运行该程序以获得更好的结果。届时将加载所有启动应用程序。(10分钟----取决于启动应用程序的数量和启动每个应用程序所需的时间)
测量的时间有两个组成部分
如果您正在从磁盘读取文件,并将其加载到内存中 - 并排序:
1)读取文件并将其存储在数组中的时间 2)排序时间
这些是分开测量的吗?
你能看看这个吗? 使 Linux 缓冲区缓存失效
如果重复清除缓存的实验得到相同的结果,而不是重新启动,那么您可以推断文件缓冲区缓存效果没有被考虑在内。