什么是缓冲区机制:
缓冲区是内存空间的一部分,在内存中预留了一定的存储空间,用来暂时保存输入和输出等I/O操作的一些数据,这些预留的空间就叫做缓冲区;缓冲区有buffer缓冲区和Cache缓存区两种,但是这篇主要介绍buffer缓冲区
为什么要设置缓冲区
原因:高速设备与低速设备的不匹配,势必会让高速设备花时间等待低速设备,我们可以在这两者之间设立一个缓冲区,从而使低速输入输出设备和高速的cpu可以协调工作,避免低速输入输出设备占用缓冲区,解放cpu。
(1)减少CPU对磁盘的读写次数:CPU读取磁盘中的数据并不是直接读取磁盘,而是先将磁盘的内容读入到内存,也就是缓冲区,然后CPU对缓冲区进行读取,进而操作数据;计算机对缓冲区的操作时间远远小于对磁盘的操作时间,大大的加快了运行速度。下面一个图片描述的就是这样的一个过程
(2)提高CPU的执行效率:比如说使用打印机打印文档,打印的速度是相对比较慢的,我们操作CPU将要打印的内容输出到缓冲区中,然后CPU转手就可以做其他的操作,进而提高CPU的效率
(3)合并读写(减少读写次数):如果每次数据只传输一点数据,就需要传送很多次,这样会浪费很多时间,因为开始读写与终止读写所需要的时间很长,如果将数据送往缓冲区,待缓冲区满后再进行传送会大大减少读写次数,这样就可以节省很多时间。例如:我们想将数据写入到磁盘中,不是立马将数据写到磁盘中,而是先输入缓冲区中,当缓冲区满了以后,再将数据写入到磁盘中,这样就可以减少磁盘的读写次数,不然磁盘很容易坏掉。再例如:对于一个文件的数据,先读取后写入,循环执行10次,然后关闭文件,如果存在缓冲机制,那么就可能只有第一次读和最后一次写是真实操作,其它的操作都是在操作缓存
缓冲区的分类
buffer缓冲区存储速度不同步的设备或者优先级不同的设备之间的传输数据,比如键盘、鼠标等,此外,buffer一般是用在写入磁盘的
Cache缓存区是位于CPU和主内存之间的容量较小但速度很快的存储器,Cache保存着CPU刚用过的数据或循环使用的数据;Cache缓存区的运用一般是在I/O的请求上
缓存区按性质分为两种,一种是输入缓冲区,另一种是输出缓冲区。对于C、C++程序来言,类似cin、getchar等输入函数读取数据时,并不会直接从键盘上读取,而是遵循着一个过程:cingetchar --> 输入缓冲区 --> 键盘,我们从键盘上输入的字符先存到缓冲区里面,cingetchar等函数是从缓冲区里面读取输入;那么相对于输出来说,程序将要输出的结果并不会直接输出到屏幕当中区,而是先存放到输出缓存区,然后利用coutputchar等函数将缓冲区中的内容输出到屏幕上。cin和cout本质上都是对缓冲区中的内容进行操作。
缓存(cache)与缓冲(buffer)的主要区别:
Buffer的核心作用是用来缓冲,缓和冲击。比如你每秒要写100次硬盘,对系统冲击很大,浪费了大量时间在忙着处理开始写和结束写这两件事嘛。用个buffer暂存起来,变成每10秒写一次硬盘,对系统的冲击就很小,写入效率高了,极大缓和了冲击。
Cache的核心作用是加快取用的速度。比如你一个很复杂的计算做完了,下次还要用结果,就把结果放手边一个好拿的地方存着,下次不用再算了。加快了数据取用的速度。
简单来说就是buffer偏重于写,而cache偏重于读。ps:大家也可以从专有名词字面上来理解 缓冲:缓解冲击,缓存:临时存储
缓冲区的类型:
缓冲区分为三大类:全缓冲、行缓冲、无缓冲
全缓冲:只有在缓冲区被填满之后才会进行I/O操作;最典型的全缓冲就是对磁盘文件的读写。(文件的写操作)
Windows下缓冲区的大小:如果我们没有自己设置缓冲区的话,系统会默认为标准输入输出设置一个缓冲区,这个缓冲区的大小通常是4096个字节的大小,这和计算机中的分页机制有关,因为进程在计算机中分配内存使用的就是分页与分段的机制,并且每个页的大小是4096个字节,因此通常情况下缓冲区的大小会设置为4096个字节的大小。可以自己写代码来测试体验
行缓冲:只有在输入或者是输出中遇到换行符的时候才会进行I/O操作。这时,我们输入的字符先存放在缓冲区,等按下回车键换行时才进行实际的I/O操作。典型代表是键盘输入数据,如下
输入操作的过程:程序调用getchar()--程序等待用户按键--输入的字符存放在键盘缓冲区--直到用户按下回车键键盘缓冲区的数据输入程序的输入缓冲区--getchar()函数开始从输入缓冲区每次读入一个字符
需要注意的是后续的getchar不会等待用户按键而是直接读取输入缓冲区中的字符直到键盘缓冲区的字符读完后等待用户按键,平时感受不到是因为输入缓冲区很大,一次性就能读完键盘缓冲区,回车后输入缓冲区就没有字符了。我们可以通过setbuf函数改变输入缓冲区大小
无缓冲:不进行缓冲,立即执行I/O操作 其中表现最明显的就是标准错误输出流(stderr),这使得出错信息尽快的返回给用户。不经常用
buffer缓冲区的刷新:指缓存被排放出来,里面所有的数据或者被写入物理介质或者被抹除掉(如果程序异常终止,输出缓冲区是不会被刷新的。当一个程序崩溃后,它所输出的数据很可能停留在输出缓冲区中等待打印。当调试一个已经崩溃的程序时,需要确认那些你认为已经输出的数据确实已经刷新了。否则,可能将大量时间浪费在追踪代码为什么没有执行中,而实际上代码已经执行了,只是程序崩溃后缓冲区没有被刷新,输出数据被挂起没有打印而已。)
引发刷新的条件:
(1)缓冲区满
(2)程序正常结束作为main返回工作的一部分,将清空所有的输出缓冲区。
(3)用操作符刷新缓冲区 flush 和endl 操作符刷新:
▪flush:刷新缓冲区但是不会添加任何字符
▪endl:输出一个换行符并刷新缓冲区
(\n:没有刷新缓冲区的作用
ends:在缓冲区插入空字符\0但是不刷新
cerr:标准错误输出 cerr<<”Error1…”<<endl;)
(4)关闭文件
(在C++中,cin, cout, cerr 分别于stdin, stdout, stderr对应的。即iostream流对象分别与cstdio对应/因为默认情况下,cin是和cout绑定的,cin 会刷新cout的缓冲区,可以用函数cin.tie(0)来解绑定)