有fread($file, 8192)
比 更好或更安全的fread($file, 10000)
吗?为什么大多数示例使用 2 的幂?
3 回答
请参阅这个问题的公认答案:How do you determine the Ideal buffer size when using FileInputStream? .
大多数文件系统配置为使用 4096 或 8192 的块大小。理论上,如果您配置缓冲区大小以便读取比磁盘块多几个字节,则对文件系统的操作可能非常低效(即,如果您将缓冲区配置为一次读取 4100 个字节,每次读取需要文件系统读取 2 次块)。如果这些块已经在缓存中,那么您最终会付出 RAM -> L3/L2 缓存延迟的代价。如果你不走运并且块还没有在缓存中,那么你也要付出磁盘-> RAM 延迟的代价。
这就是为什么您会看到大多数缓冲区大小为 2 的幂,并且通常大于(或等于)磁盘块大小。这意味着您的一个流读取可能会导致多个磁盘块读取 - 但这些读取将始终使用完整块 - 不会浪费读取。
尽管这个问题与 Java 相关,但答案却不是。此外,它几乎与语言无关。该答案涵盖了我所知道的有关缓冲区大小的所有因素。
要么是因为:
- 选择任意数字的程序员喜欢选择两个权力,或
- 在某种过早的优化中,程序员认为读取块大小的倍数会带来某种速度提升。
操作系统以页为单位分配内存(通常为 4k - 但有时为 8k)。
在这种情况下,使用 8192 字节的倍数的缓冲区大小可以提高内存分配的效率(因为它也适合 4096 字节的倍数)。
如果您请求 13k 的内存,无论如何都会使用 16k,所以为什么不从 16k 开始。
CPU 指令集也经过优化,可以处理与某些边界对齐的数据,无论是 32、64 还是 128 位。使用与 3 位或 5 位或其他奇怪的数据对齐的数据会增加额外的处理开销。
这不是特定于 PHP 的,它在操作系统自己的内存管理之上使用 Zend 内存管理器,并且可能会预先分配更大的内存块,并将内存管理的问题从用户身上转移开。