我正在玩文件读/写,但很难决定为读取"读取"系统调用。
特别是,我正在考虑" http://pubs.opengroup.org/onlinepubs/009695399/functions/read.html"
除了SSIZE_MAX之外,它似乎没有说明我可以一次读取多少字节。
更糟糕的是,如果我使用SSIZE_MAX字符创建一个数组,程序会产生一个:
sh: ./codec: Bad file number
有没有合理的方法来决定每次读取系统调用要读取多少字节?我担心的是,这可能会因系统而异(我不能只读取尽可能多的读数,直到读取无法确定我能读取的确切字节数,即使我这样做,它也会赢得&t; t必须比读取更少的字节更快。)
我的一个想法是检查我的CPU缓存大小并尝试使我的缓冲区不大于此,但由于我不知道CPU缓存如何工作,我不确定这是否一定是正确的。< / p>
提前致谢。
答案 0 :(得分:4)
我思考的问题基本相同,我得出一个非常简单的结论:
使用保守的默认或启发式操作,但如果需要,请让用户轻松覆盖它。
您会看到,在某些情况下,用户可能不希望实用程序获得最大吞吐量,但可能会在后台执行任何操作。也许这项任务并不那么重要。就个人而言,在Linux中,我经常使用ionice
和st_blksize
实用程序将长期但不优先的任务放在次要位置,可以这么说,这样他们就不会干扰我的实际工作
过去十年的基准表明128k到2M的块大小(2 17 到2 21 字节)始终如一地运行良好 - 几乎所有的最佳速率都不远情况 - 平均值缓慢向该范围的较大端移动。通常情况下,两种尺寸的功率似乎比非功率两种功能更好,尽管我没有看到足够的各种RAID配置基准来完全信任。
因为你的实用程序几乎肯定会为每个新的硬件类型/代重新编译,我更喜欢在编译时定义一个默认的块大小,但是在运行时将它简单地覆盖(通过命令行选项) ,环境变量和/或配置文件)。
如果您的实用程序是针对当前的POSIXy操作系统打包的,则二进制文件可以使用默认设置,该默认设置似乎最适合在该计算机上完成的任务类型;例如,Raspberry Pis和其他SBC通常没有那么多内存,因此较小(例如,65536字节)的默认块大小可能效果最好。桌面用户可能不关心内存耗尽,因此您可能会在当前桌面计算机上使用更大的默认块大小。
(服务器和高性能计算(这是我对此进行思考的地方),块大小基本上是基于确切的硬件和工作负载进行基准测试,或者只是一个几乎没有通知的猜测。通常后者。)
或者,您可以根据所涉及文件的{{1}}构建一个启发式算法,可能乘以一个默认因子,并将其限制在一些首选范围内。然而,随着硬件的变化,这种启发式方法往往会快速腐烂。
通过启发式方法,重要的是要记住,这个想法不是要始终达到最佳效果,而是要避免真正糟糕的结果。如果用户想要挤出最后几个百分点的性能,他们可以在自己的工作流程中进行一些基准测试,并相应地调整默认值。 (我个人有,并且做。)
答案 1 :(得分:0)
在您要阅读的文件上调用stat()
或fstat()
。 struct stat
成员st_blksize
包含您应该用于从您调用stat()
的文件中读取的最佳缓冲区大小。
答案 2 :(得分:0)
那么,确定适当的缓冲区大小完全取决于问题。首先,我将检查缓冲区大小的最新技术状态:stdio
使用BUFSZ
作为缓冲区大小(通常是一个unix磁盘块的大小,一旦固定为512,并且可能现在有点介于1024和4096之间---从磁盘块大小到虚拟页面大小---)这对于在这里移动的数量而言是远低的,但是是一个很好的(并且被认为)可接受的值。
另一方面,考虑一个只有8Kb内存的嵌入式系统,并使用一兆字节的缓冲存储。使用虚拟内存进行缓冲存储(如果允许)听起来有些奇怪。
假设您正在设计文件复制实用程序,其中最佳缓冲区大小确定将是最佳的。可能认为最大的可接受价值是必须的。但经过一些测试,你会得到很多误用的记忆。假设您设计的流程只使一个线程充当读者和作者。您读取数据,然后将该数据写入另一个文件。第一件事是你使用的内存不会影响,因为它只影响你的进程的写入和读取顺序......如果一个读取意味着一个磁盘读取(假设一次一个块)磁盘块大小以上的东西不会让你进行额外的读取来获得相同的数据(这实际上是在系统级完成的,它可以缓冲你的数据,使得在单个字节块中读取数据成为可能,同时系统正在逐块读取数据
第二种方法是最小化系统调用。在这一点上,每个人都知道进行系统调用是一件昂贵的事情,所以如果我们可以安排进行最小的系统调用,我们就会得到一些好的东西。但过了一段时间,你会发现没有额外的性能,因为系统正在逐块读取你的数据,你的进程正在等待它,使系统调用惩罚完全不可见,因为它代表不到1%等待时间。此外,系统必须保证您的数据不会同时发生变化,进行原子读取调用(这是通过从头到尾锁定文件的inode来完成的)所以没有进程可以实际引用相同的文件直到你完成通话。允许大缓冲区,使您的进程可能太大而无法放入内存并使用额外的交换处理加载系统。这使你在进入大缓冲区之前要小心。
最后,与使用大缓冲区产生的额外系统调用惩罚相比,额外的系统调用惩罚是微不足道的,完全没用。如果你住的是一个正常大小的系统(让我们假设一台笔记本电脑或台式电脑的内存量为2-8Gb),那么8Kb的缓冲区大小可能适用于所有场景。
最后要考虑的是音频/视频流缓冲区大小确定。在这种情况下,通常有一个生产者(要再现的数据的读者)以不同的速度生成数据(例如,在网络负载上随时间变化)和以固定速率吃掉这些数据的消费者(假设为8kbps) telco呼叫,用于cd播放的192kbps等)缓冲区大小必须允许补偿数据提供速度变化以不清空缓冲区,因此,我们将有一个无声时段来填补空白。这本质上是动态的,您必须预先计算可能的网络数据包丢失和重传允许。通过延迟消费者并使用流数据填充一些缓冲区,您可以补偿并使数据消费者满意而不会丢失数据。在这种情况下,2Mb的流缓冲在某些情况下是常识,具体取决于您想要承担的数据丢失,重传时间和流质量的概率。