作者tomex (tomex_ou)
看板C_Sharp
标题[心得]Buffer与Stream的因果
时间Wed Nov 2 10:58:29 2005
编程中所谓的Buffer(暂存)可以说是一种资料操作的概念,大凡就字面上大家都懂
但若非有实作经验过,否则对它的运作方式及差别,则会模糊而似懂非懂,我就是
这样一个过来人....然而,经过网路Socketing剖析及queue状循环使用资料的实务
经验後(使用C++),我慢慢得到一个清晰的感受。
Buffer的需求
-------------
当我们要对一堆资料作操作,必须建立所谓的位元阵列来摆放实际资料,然而当资
料量太大时,我们必须分批次地用此阵列来处理,如:
int totalDataSize = 99999;
while (totalDataSize > 0)
{
int arraySize = processArray(100); // 复制至阵列且作运算。
totalDataSize = totalDataSize - arraySize;
}
但totalDataSize值非常大时,整个while都在运作中,cpu时间都被它占走了,而实
务上还有其他事情等待cpu处理,因此用while()来处理大资料,是不切实际的单纯
想法。况且每一次的while()执行後,阵列的值都被洗掉了...
既然记忆体有限,我们只要找延伸性的替代,就是File(档案)。为了避免档案写入
一直无限扩大,我们会在超过某大小後回到Position=0重新写档,形成一个环状资
料带。嗯,问题解决了,然而档案读写操作不够快且单一磁头竞争下,效率很差。
因此最好是能在记忆体配置某大小的暂存区,而最终会写入档案,这块担任中间媒
介的洗钱记忆体的就叫做Buffer,它是用来增加读写效率的。其实,硬碟本身有它
的Buffer记忆体,而OS写档操作也是有内建Buffer空间,但这些我们无法控制大小
及写入时间,因此必须实作自己的Buffer机制。
Stream概念的产生
-----------------
「配置一块记忆体当Buffer,等满了再写入档案」就是这架构。纸上当兵大家都会
,但怎麽实作呢?如何撰写一个机制,让Buffer写入档案的动作是自动化而不用让
使用者担心写读的时间点呢?於是这种自动化延伸Buffer的机制被实作,就称为「
Stream(串流)」的概念。使用者只要设定好Stream最终写入的装置,且设定好这个
Stream的内建Buffer大小,其实就只要Read()/Write()即可。
Stream就像是一个连接带,一个河川,一直延伸写入着,当你要读取资料时,只要
设定它的Position,即可读取出来。然而一个Stream的写入点及读写点只提供一个
因此要同时读写,就必须透过两个执行绪(Read/Write)来控制这个Stream的Position。
虽然同属一个Stream结构,在写入点附近的位置,其实际读写装置是Buffer记忆体,
读写最快但也是容易Write/Read相冲突的地方,这需要靠逻辑去避免读写正在写入的
区块。而这部分,就是实务上,我们必须自己去依案例实作的地方。
结论
-----
Buffer只是一种概念,由上文得知,称呼的地方却完全不同。它可以是一个记忆体内
某固定长度阵列(1),也可以指档案(2),更可以指整个Stream机制(3),或是单指某
Stream中的Buffer记忆体(4)…等四种。我在网路Socket程式的实作中,为了接收资料
来作剖析,遇到第1种(阵列)的瓶颈而创作了第3种(stream)的Queue循环使用,最後
面临记忆体有限的现实,把Buffer实作在第2种(档案)方式上,再增加读写效率而内建
第4种的机制。
这样土法炼钢後,再去使用.Net中的IO物件,完全清楚它的设计理念及使用时机了!
这些MemoryStream/FileStream/BufferedStream/NetworkStream/CryptStream及
各式SteamReader/Writer,都是我实作经验中的某些角色,因此当我呼叫他们时,
是真正清楚它们所担任的岗位呀。这些.Net物件我之前已研究了三次,是会用但不知
其背後的原理及差别,如此透过C++来实作它们,再回归C#来使用它们,别有一番不同
的感受。
--
贯彻分享精神
我为人人,人人为我
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 211.78.132.15
1F:推 liunate:好文好文 11/02 12:50
2F:→ imprazaguy:m起来吧 11/02 21:20
3F:推 asuka05:push 11/05 19:33