我有一个程序,其目的是从一些输入文本文件中读取,将所有可打印的字符(即 32 到 126 之间的 ASCII)过滤到其他一些输出文本文件中。
我还得到一个参数"DataAmount"——这意味着我需要读取的数据量——可能是 1B、1K、1M、1G、80000B 等(任何自然数都可以在单位之前)。
这不是输入文件的大小,而是我需要从输入文件中读取多少。如果输入文件小于数据量,我需要重新读取文件,直到我准确地读取数据量字节。
对于过滤,我从输入文件读取到某个缓冲区中。我从缓冲区过滤到其他一些缓冲区的可打印字符,并从该缓冲区写入输出文件(两个缓冲区的大小相同)。
问题是,我如何确定这两个缓冲区的最佳大小,因此对 read() 和 write() 的调用最少?
(注意:我不会一次写入整个数据,因为它可能太大,并且我不会一次写入每个字节。我仅在缓冲区已满时才从输出写入输出文件)。
目前,我构建的缓冲区大小仅取决于单位:
如果是 B 或 K,大小将为 1024。
如果是 M 或 G,则大小为 4096。
这根本不好,因为对于 1B 和 100000B,我将拥有相同大小的缓冲区。
我怎样才能改善这一点?
我个人的经验是,只要您使用几千字节,缓冲区大小就无关紧要。
正如您在问题中指出的,执行系统调用存在开销,因此一次执行一个字符的 I/O 效率不是很高,您可以通过读取和写入更大的块来减少开销。 但是,还有其他事情需要时间,任何合理的缓冲量都会降低您的系统调用开销,直到其他事情花费大部分时间。 此时,较大的缓冲区不会使程序明显更快。 使缓冲区太大也存在问题,因此您也可以朝这个方向出错。
我不会像您那样使缓冲区大小动态化。 它为程序带来了不必要的复杂性。 您可以通过使用不同的缓冲区大小运行程序来验证这一点,并查看它会产生什么样的差异。
至于要使用的实际值,stdio.h 头文件定义了宏 BUFSIZ,这是 stdio 缓冲区的默认大小。 该宏是合理的使用大小。
另请注意,如果您使用 stdio 函数来执行 I/O,它们已经提供了缓冲(如果您不直接调用系统调用 read() 和 write(),那么您使用的是 stdio。 实际上没有理由缓冲数据两次,因此您可以一次执行一个字符的 I/O 并让 stdio 缓冲区为您处理它,或者使用 setvbuf() 禁用 stdio 缓冲。
如果你以前知道输入,你可以得到一些统计数据并得到平均值,所以它不是一个固定的大小,而是一个近似值。
但我建议你:不要担心read
和close
系统调用。如果您从 imput 中读取很少的数据并且缓冲区很高,则会浪费一些字节。如果你得到一个很大的输入并且有一点缓冲区,你只需要做一些额外的迭代。
缓冲区的中等大小会很好。例如,512。
确定单位后,确定单位数是否需要额外的缓冲区大小。因此,找到B后,请检查该值。这样,您就不必拆分较小的单元。
您可以对单位指示器执行 switch 语句,然后根据该单位的数值在每个案例中进行处理。例如,对于B,执行最大值的整数除法,并根据结果设置实际缓冲区大小(再次在开关/案例序列中)。