Node.js Undocumented(1)
Node.js Undocumented(2)
写这种系列blog,是为了监督自己,不然我估计我不会有动力写完。这一节,我将介绍下Buffer这个module。js本身对文本友好,但是处理二进制数据就不是特别方便,因此node.js提供了Buffer模块来帮助你处理二进制数据,毕竟node.js的定位在网络服务端,不能只对文本协议友好。
Buffer模块本身其实没有多少未公开的方法,重要的方法都在文档里提到了,有两个方法稍微值的提下。
Buffer.get(idx)
跟buffer[idx]是一样的,返回的是第idx个字节,返回的结果是数字,如果要转成字符,用String.fromCharCode(code)即可。
Buffer.inspect()
返回Buffer的字符串表示,每个字节用十六进制表示,当你调用console.dir的时候打印的就是这个方法返回的结果。
Buffer真正值的一提的是它的内部实现。Buffer在node.js内部的cpp代码对应的是SlowBuffer类(src/node_buffer.cc),但是两者之间并不是一一对应。
对于创建小于8K的Buffer,其实是从一个pool里slice出来,只有大于8K的Buffer才是每次都new一个SlowBuffer。查看源码(lib/buffer.js):
Buffer.poolSize
=
8
*
1024
;
if
(
this
.length
>
Buffer.poolSize) {
//
Big buffer, just alloc one.
this
.parent
=
new
SlowBuffer(
this
.length);
this
.offset
=
0
; }
else
{
//
Small buffer.
if
(
!
pool
||
pool.length
-
pool.used
<
this
.length) allocPool();
this
.parent
=
pool;
this
.offset
=
pool.used; pool.used
+=
this
.length; }
因此,我们可以修改Buffer.poolSize这个“静态”变量来改变池的大小
Buffer.poolSize
Buffer类创建的池大小,大于此值则每次new一个SlowBuffer,否则从池中slice返回一个Buffer,如果池剩余空间不够,则新创建一个SlowBuffer做为池。下面的例子打印这个值并修改成16K:
console.log(Buffer.poolSize); Buffer.poolSize
=
16
*
1024
;
SlowBuffer类
SlowBuffer类我们可以直接使用的,如果你不想使用Buffer类的话,SlowBuffer类有Buffer模块的所有方法实现,例子如下:
var
SlowBuffer
=
require('buffer').SlowBuffer
var
buf
=
new
SlowBuffer(
1024
) buf.write(
"
hello
"
,'utf
-
8
'); console.log(buf.toString('utf
-
8
',
0
,
5
)); console.log(buf[
0
]);
var
sub
=
buf.slice(
1
,
3
); console.log(sub.length);
请注意,SlowBuffer默认不是Global的,需要require buffer模块。
使用建议和性能测试
Buffer的这个实现告诉我们,要使用好Buffer类还是有讲究的,每次创建小于8K的Buffer最好大小刚好能被8k整除,这样能充分利用空间;或者每次创建大于8K的Buffer,并充分重用。我们来看一个性能测试,分别循环1000万次创建16K,4096和4097大小的Buffer,看看耗时多少:
function
benchmark(size,repeats){
var
total
=
0
; console.log(
"
create %d size buffer for %d times
"
,size,repeats); console.time(
"
times
"
);
for
(
var
i
=
0
;i
<
repeats;i
++
){ total
+=
new
Buffer(size).length; } console.timeEnd(
"
times
"
); }
var
repeats
=
10000000
; console.log(
"
warm up
"
) benchmark(
1024
,repeats); console.log(
"
start benchmark
"
) benchmark(
16
*
1024
,repeats); benchmark(
4096
,repeats); benchmark(
4097
,repeats);
创建1024的Buffer是为了做warm up。在我机器上的输出:
start benchmark create
16384
size buffer
for
10000000
times times: 81973ms create
4096
size buffer
for
10000000
times times: 80452ms create
4097
size buffer
for
10000000
times times: 138364ms
创建4096和创建4097大小的Buffer,只差了一个字节,耗时却相差非常大,为什么会这样?读者可以自己根据上面的介绍分析下,有兴趣的可以留言。 另外,可以看到创建16K和创建4K大小的Buffer,差距非常小,平均每秒钟都能创建10万个以上的Buffer,这个效率已经足以满足绝大多数网络应用的需求。
文章转自庄周梦蝶 ,原文发布时间2011-06-04
相关资源:敏捷开发V1.0.pptx