数据缓冲策略 —— 无缓冲、行缓冲、全缓冲(缓冲区大小测试)

数据缓冲策略 —— 无缓冲、行缓冲、全缓冲(缓冲区大小测试)结合代码介绍不缓冲、行缓冲、全缓冲,使用例子进一步了解三种缓冲的特性

printf打印数据时,一般会先把数据放入C缓冲区,然后再刷新到内核缓冲区,最后再写入硬件

这个过程中,数据从C缓冲区迁移到内核缓冲区的操作我们称为缓冲(也可以理解为刷新)

下面我们将介绍 缓冲策略的三种情况

1、无缓冲(不刷新),如write

2、行缓冲(行刷新),遇到换行符\n才会刷新

3、全缓冲(缓冲区满了才刷新),如写入数据到磁盘


目录

一、无缓冲(不刷新)

1、无缓冲验证

2、验证结果

二、行缓冲

1、不加 ‘\n’ 验证

2、添加 ‘\n’ 验证

三、全缓冲

1、打印少量的数据

2、打印大量的数据

3、缓冲区大小验证

四、缓冲案例:行缓冲 变成了 全缓冲

1、案例介绍

 2、案例分析


一、无缓冲(不刷新)

不缓冲的意思就是,不会向内核缓冲区存入内容,而是直接输出到文件中,比如系统调用函数 write函数

数据缓冲策略 —— 无缓冲、行缓冲、全缓冲(缓冲区大小测试)

1、无缓冲验证

下面用一段简单的代码来验证这一现象,基本思路是:调用write函数向文件里写入内容,使用死循保证当前进程不会退出(退出的时候会刷新缓冲区)。新开一个终端查看文件内容,如果文件中包含了写入的内容,说明是无缓冲;如果不包含写入的内容,说明是其他缓冲。

测试代码如下:

int main(int argc, char** argv){
	int fd = open("./1.txt",O_WRONLY | O_APPEND);
	const char* buf = "hello, world";
	write(fd, buf, strlen(buf));        // 注意这里使用的是strlen,而不是sizeof
                                        // sizeof(buf) 就会变成计算buf指针的大小,那就是固定4个字节

	while(1)
	{
		sleep(1000);
	}
	close(fd);
	return 0;
}

2、验证结果

验证结果如下:

数据缓冲策略 —— 无缓冲、行缓冲、全缓冲(缓冲区大小测试)

我们发现, 进程还没有退出的情况下,字符串就已经被写入到文件里了,说明write函数没有经过内核缓冲区,直接将数据写入到文件中。

二、行缓冲

行缓冲的意思是,遇到换行符的时候才会将数据从内核缓冲区刷新到 磁盘文件。最典型的就是printf 函数,printf函数中如果不加 ‘\n’,那就只是全缓冲,如果遇到了‘\n’,此时会立马将数据刷新到 stdout 流。

1、不加 ‘\n’ 验证

验证的基本思路:不加‘\n’,同时不让进程退出,如果printf 可以打印内容,说明不是行缓冲;如果不行,可以看一下接下来的添加 ‘\n’ 验证。测试代码如下:

int main(int argc, char** argv){
	printf("hello, world");        // 不加'\n'

	while(1)
	{
		sleep(1000);
	}
	close(fd);
	return 0;
}

数据缓冲策略 —— 无缓冲、行缓冲、全缓冲(缓冲区大小测试)

此时printf 并没有打印内容,说明此时数据很有可能还留在内核缓冲区里。 

2、添加 ‘\n’ 验证

验证的基本思路:如果加了’\n’以后,可以看到打印的内容,说明是行缓冲;如果没有,说明是其他缓冲。

int main(int argc, char** argv){
	printf("hello, world\n");        // 加'\n'

	while(1)
	{
		sleep(1000);
	}
	close(fd);
	return 0;
}

数据缓冲策略 —— 无缓冲、行缓冲、全缓冲(缓冲区大小测试)

三、全缓冲

全缓冲的意思是,只有等缓冲区满了以后,才会将内核缓冲区里的数据刷新到磁盘文件。printf函数在没有加 ‘\n’ 的时候就是典型的 全缓冲。我们可以通过打印少量的数据、打印大量的数据来验证。

1、打印少量的数据

此时我们只输出 20 个字符看一下是否会打印出来。

int main(int argc, char** argv){
    for(int i = 0; i < 20; i++)
    {
        printf("x");       
    }
	

	while(1)
	{
		sleep(1000);
	}
	close(fd);
	return 0;
}

数据缓冲策略 —— 无缓冲、行缓冲、全缓冲(缓冲区大小测试)

 从这里可以看出,缓冲区的大小是大于 20 个字节的。

2、打印大量的数据

此时我们改为输出 2000 个字符来看一下是否会打印。

int main(int argc, char** argv){
    for(int i = 0; i < 2000; i++)
    {
        printf("x");       
    }
	

	while(1)
	{
		sleep(1000);
	}
	close(fd);
	return 0;
}

数据缓冲策略 —— 无缓冲、行缓冲、全缓冲(缓冲区大小测试)

从这里可以看出,缓冲区的大小是小于 2000 的,那么缓冲大小到底有多少呢?

3、缓冲区大小验证

可以算一下图中打印了多少个’x’,我们使用在线字符统计工具看一下。正好是 1K

数据缓冲策略 —— 无缓冲、行缓冲、全缓冲(缓冲区大小测试)

四、缓冲案例:行缓冲 变成了 全缓冲

1、案例介绍

test.c 的代码如下

数据缓冲策略 —— 无缓冲、行缓冲、全缓冲(缓冲区大小测试)

 然后我们在命令行里输入

数据缓冲策略 —— 无缓冲、行缓冲、全缓冲(缓冲区大小测试)

 2、案例分析

(1) 11行~16行:printf函数运行

——》每运行一行printf,数据会先存入C缓冲区,遇到\n,立即刷新到文件内核缓冲区, 这个是行刷新(行缓冲),正准备刷新的时候发现了重定向符号 ‘ > ’ 

——》重定向符号 ‘ > ’  断开原本的fd = 1 和 stdout之间的关系,然后指向 log.txt(向磁盘文件写入内容是全缓冲

——》结果行缓冲 变成了 全缓冲(这就导致 I/O缓冲区的内容不会立即刷新)

行缓冲:遇到\n立即刷新C缓冲区,即 把C缓冲区的内容迁移到内核缓冲区

全缓冲:等C缓冲区满了再刷新到内核缓冲区,即暂不迁移

到这一步,打印的内容不会输出到stdout文件,或者log.txt 文件,而是留在了内核缓冲区里。此时又因为调用了 close(1),close(1) 断开了内核缓冲区和磁盘文件之间的联系,这就导致数据永远留在了内核缓冲区。

数据缓冲策略 —— 无缓冲、行缓冲、全缓冲(缓冲区大小测试)

今天的文章数据缓冲策略 —— 无缓冲、行缓冲、全缓冲(缓冲区大小测试)分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/31113.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注