Node.js Undocumented(2)
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;
}
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;
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);
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);
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
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
最後更新:2017-05-18 18:04:53