我有这个简单的 hello world 程序:
#include <stdio.h>
int main() {
printf("Hello, world!\n");
return 0;
}
我像平常一样用 LLVM Clang(v15.0.1,从 Homebrew 构建,所以不是 Apple 版本)编译了这个程序,然后运行并计时输出。令我惊讶的是,程序第一次运行的时间比第二次长了近 10 倍,但接下来的 3 次执行运行速度要快得多。
$ clang test.c -o test
$ time ./test
Hello, world!
real 0m0.169s
user 0m0.001s
sys 0m0.002s
$ time ./test
Hello, world!
real 0m0.017s
user 0m0.001s
sys 0m0.006s
$ time ./test
Hello, world!
real 0m0.004s
user 0m0.001s
sys 0m0.002s
$ time ./test
Hello, world!
real 0m0.008s
user 0m0.001s
sys 0m0.005s
我在 Intel Core i5 mac 上运行此程序,运行 macOS Big Sur v11.6.8。 shell 是 macOS 附带的
bash
。
我的代码中没有任何内容涉及时间,而且我认为没有任何内容可以缓存,所以我不确定为什么第一次执行运行得这么慢。我怀疑操作系统可能正在进行某种优化,但我不知道是什么/如何进行。造成运行时间如此巨大差异的原因是什么?
您观察到的行为可能是由于现代操作系统处理可执行文件首次执行的方式所致。这称为“文件系统缓存”或“磁盘缓存”。当您第一次执行程序时,操作系统将程序从磁盘加载到内存中,后续执行速度要快得多,因为操作系统在内存中保留了程序的缓存副本。
以下是第一次和后续运行期间通常会发生的情况:
第一次执行:
操作系统将可执行文件“test”从磁盘加载到内存中。 程序被执行,并显示输出。 由于是第一次运行程序,操作系统没有缓存副本,从磁盘读取并将程序加载到内存需要一些时间,这导致执行时间较长。 后续处决:
操作系统在第一次执行时就已经在内存中缓存了“测试”程序的副本。 直接使用缓存的副本,无需从磁盘读取,从而实现更快的执行时间。 正如您所观察到的,后续执行比第一次执行要快得多。您在第一次和第二次执行之间看到的时间差异可能是由于操作系统的磁盘缓存和内存缓存行为造成的。在后续运行中,程序的二进制和库依赖项可能仍驻留在内存中,这使得执行速度更快。
此外,您看到的时间差异也可能受到不同执行期间系统上运行的其他后台进程的影响。
此行为并非 macOS 特有;提高经常执行的程序的整体性能是现代操作系统的一个常见功能。
如果您想获得更一致的程序执行时间基准,您可以多次运行它,并在初始缓存预热后从这些运行中获取平均时间。