确定 linux 中读取文件的最佳缓冲区大小
determining the optimal buffer size for file read in linux
我正在编写一个从 stdin 读取并写入 stdout 的 C 程序。但它缓冲数据,以便仅在读取特定数量的字节后才执行写入(=SIZE)
#include<stdio.h>
#include<stdlib.h>
#define SIZE 100
int main()
{
char buf[SIZE];
int n=0;
//printf("Block size = %d\n", BUFSIZ);
while( ( n = read(0, buf, sizeof(buf)) ) > 0 )
write(1, buf, n);
exit(0);
}
我运行在 Oracle Virtual Box(4GB RAM,2 核)上托管的 Ubuntu 18.04 上运行此程序,并针对不同的缓冲区大小值测试该程序。我已经将标准输入重定向到一个文件(其中包含动态创建的随机数)并将标准输出重定向到 /dev/null。这是用于 运行 测试的 shell 脚本:
#!/bin/bash
# - step size (bytes)
# - start size (bytes)
# - stop size (bytes)
echo "Changing buffer size from to in steps of , and measuring time for copying."
buff_size=
echo "Test Data" >testData
echo "Step Size:(doubles from previous size) Start Size: Stop Size:" >>testData
while [ $buff_size -le ]
do
echo "" >>testData
echo -n "$buff_size," >>testData
gcc -DSIZE=$buff_size copy.c # Compile the program for cat, with new buffer size
dd bs=1000 count=1000000 </dev/urandom >testFile #Create testFile with random data of 1GB
(/usr/bin/time -f "\t%U, \t%S," ./a.out <testFile 1>/dev/null) 2>>testData
buff_size=$(($buff_size * 2))
rm -f a.out
rm -f testFile
done
我正在测量执行程序所花费的时间并将其制成表格。测试 运行 产生以下数据:
Test Data
Step Size:(doubles from previous size) Start Size:1 Stop Size:524288
1, 5.94, 17.81,
2, 5.53, 18.37,
4, 5.35, 18.37,
8, 5.58, 18.78,
16, 5.45, 18.96,
32, 5.96, 19.81,
64, 5.60, 18.64,
128, 5.62, 17.94,
256, 5.37, 18.33,
512, 5.70, 18.45,
1024, 5.43, 17.45,
2048, 5.22, 17.95,
4096, 5.57, 18.14,
8192, 5.88, 17.39,
16384, 5.39, 18.64,
32768, 5.27, 17.78,
65536, 5.22, 17.77,
131072, 5.52, 17.70,
262144, 5.60, 17.40,
524288, 5.96, 17.99,
由于我们使用了不同的块大小,所以我没有看到用户+系统时间有任何显着变化。但从理论上讲,随着块大小变小,同样的文件大小会产生很多系统调用,执行时间应该会更长。我在理查德·史蒂文斯 (Richard Stevens) 的书 'Advanced Programming in Unix Environment' 中看到了类似测试的测试结果,它表明如果复制中使用的缓冲区大小接近块大小,则用户+系统时间会显着减少。(在我的例子中,块大小在 ext4 分区上是 4096 字节)
为什么我无法重现这些结果?我是否遗漏了这些测试中的某些因素?
您没有在源代码中禁用行 #define SIZE 100
,因此通过选项 (-DSIZE=1000
) 的定义确实只影响此 #define
。在我的编译器上,我在编译时收到一个警告 (<command-line>:0:0: note: this is the location of the previous definition
)。
如果您注释掉 #define
,您应该能够修复此错误。
想到的另一个方面:
如果你在一台机器上创建一个文件并在之后立即读取它,它将在 OS 的磁盘缓存中(它足够大以存储所有这个文件),所以实际磁盘块大小在这里不会有太大影响。
Stevens 的书写于 1992 年,当时 RAM 比现在贵得多,所以其中的一些信息可能已经过时了。我也怀疑这本书的新版本是否删除了这些内容,因为一般来说它们仍然是正确的。
我正在编写一个从 stdin 读取并写入 stdout 的 C 程序。但它缓冲数据,以便仅在读取特定数量的字节后才执行写入(=SIZE)
#include<stdio.h>
#include<stdlib.h>
#define SIZE 100
int main()
{
char buf[SIZE];
int n=0;
//printf("Block size = %d\n", BUFSIZ);
while( ( n = read(0, buf, sizeof(buf)) ) > 0 )
write(1, buf, n);
exit(0);
}
我运行在 Oracle Virtual Box(4GB RAM,2 核)上托管的 Ubuntu 18.04 上运行此程序,并针对不同的缓冲区大小值测试该程序。我已经将标准输入重定向到一个文件(其中包含动态创建的随机数)并将标准输出重定向到 /dev/null。这是用于 运行 测试的 shell 脚本:
#!/bin/bash
# - step size (bytes)
# - start size (bytes)
# - stop size (bytes)
echo "Changing buffer size from to in steps of , and measuring time for copying."
buff_size=
echo "Test Data" >testData
echo "Step Size:(doubles from previous size) Start Size: Stop Size:" >>testData
while [ $buff_size -le ]
do
echo "" >>testData
echo -n "$buff_size," >>testData
gcc -DSIZE=$buff_size copy.c # Compile the program for cat, with new buffer size
dd bs=1000 count=1000000 </dev/urandom >testFile #Create testFile with random data of 1GB
(/usr/bin/time -f "\t%U, \t%S," ./a.out <testFile 1>/dev/null) 2>>testData
buff_size=$(($buff_size * 2))
rm -f a.out
rm -f testFile
done
我正在测量执行程序所花费的时间并将其制成表格。测试 运行 产生以下数据:
Test Data
Step Size:(doubles from previous size) Start Size:1 Stop Size:524288
1, 5.94, 17.81,
2, 5.53, 18.37,
4, 5.35, 18.37,
8, 5.58, 18.78,
16, 5.45, 18.96,
32, 5.96, 19.81,
64, 5.60, 18.64,
128, 5.62, 17.94,
256, 5.37, 18.33,
512, 5.70, 18.45,
1024, 5.43, 17.45,
2048, 5.22, 17.95,
4096, 5.57, 18.14,
8192, 5.88, 17.39,
16384, 5.39, 18.64,
32768, 5.27, 17.78,
65536, 5.22, 17.77,
131072, 5.52, 17.70,
262144, 5.60, 17.40,
524288, 5.96, 17.99,
由于我们使用了不同的块大小,所以我没有看到用户+系统时间有任何显着变化。但从理论上讲,随着块大小变小,同样的文件大小会产生很多系统调用,执行时间应该会更长。我在理查德·史蒂文斯 (Richard Stevens) 的书 'Advanced Programming in Unix Environment' 中看到了类似测试的测试结果,它表明如果复制中使用的缓冲区大小接近块大小,则用户+系统时间会显着减少。(在我的例子中,块大小在 ext4 分区上是 4096 字节)
为什么我无法重现这些结果?我是否遗漏了这些测试中的某些因素?
您没有在源代码中禁用行 #define SIZE 100
,因此通过选项 (-DSIZE=1000
) 的定义确实只影响此 #define
。在我的编译器上,我在编译时收到一个警告 (<command-line>:0:0: note: this is the location of the previous definition
)。
如果您注释掉 #define
,您应该能够修复此错误。
想到的另一个方面:
如果你在一台机器上创建一个文件并在之后立即读取它,它将在 OS 的磁盘缓存中(它足够大以存储所有这个文件),所以实际磁盘块大小在这里不会有太大影响。
Stevens 的书写于 1992 年,当时 RAM 比现在贵得多,所以其中的一些信息可能已经过时了。我也怀疑这本书的新版本是否删除了这些内容,因为一般来说它们仍然是正确的。