浅析node的buffer模块(三读取)
by snoopyxdy
at 2013-05-08 15:37:41
original http://snoopyxdy.blog.163.com/blog/static/601174402013480524058
var buf = new Buffer(100)console.log(buf)//输出随机的一些16进制内存单元<Buffer 8b 42 0f 4d 8b 55 08 4c 39 50 ff 0f 85 61 00 00 00 48 3b 48 07 0f 83 26 01 00 00 48 8b d9 48 c1 fb 1d 48 8b 5c 18 0f 49 3b 5d b0 0f 84 10 01 00 00 48 8b ...>
这样我们的buf实例看起来就像是一个数组了Handle<Value> Buffer::MakeFastBuffer(const Arguments &args) {
HandleScope scope;
if (!Buffer::HasInstance(args[0])) {
return ThrowTypeError("First argument must be a Buffer");
}
Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args[0]->ToObject());
Local<Object> fast_buffer = args[1]->ToObject();;
uint32_t offset = args[2]->Uint32Value();
uint32_t length = args[3]->Uint32Value();
// ..省略了一些验证代码
//最主要是下面这句,将this关联索引属性
fast_buffer->SetIndexedPropertiesToExternalArrayData(buffer->data_ + offset,
kExternalUnsignedByteArray,
length);
return Undefined();
}
// toString(encoding, start=0, end=buffer.length)Buffer.prototype.toString = function(encoding, start, end) {encoding = String(encoding || 'utf8').toLowerCase(); //将encoding参数小写if (typeof start !== 'number' || start < 0) { //将start参数合法化start = 0;} else if (start > this.length) {start = this.length;}if (typeof end !== 'number' || end > this.length) { //将end参数合法化end = this.length;} else if (end < 0) {end = 0;}start = start + this.offset; //加上偏移量,这个offset很重要,代表共享buffer的偏移end = end + this.offset;switch (encoding) {case 'hex':return this.parent.hexSlice(start, end);case 'utf8':case 'utf-8':return this.parent.utf8Slice(start, end); //我们主要看这个,utf8用的比较多case 'ascii':return this.parent.asciiSlice(start, end);case 'binary':return this.parent.binarySlice(start, end);case 'base64':return this.parent.base64Slice(start, end);case 'ucs2':case 'ucs-2':case 'utf16le':case 'utf-16le':return this.parent.ucs2Slice(start, end);default:throw new TypeError('Unknown encoding: ' + encoding);}};
Handle<Value> Buffer::Utf8Slice(const Arguments &args) {HandleScope scope;Buffer *parent = ObjectWrap::Unwrap<Buffer>(args.This());SLICE_ARGS(args[0], args[1])char *data = parent->data_ + start;//static V8EXPORT Local<String> New (const char *data, int length=-1) V8手册上的说明//分配一个新的string对象Local<String> string = String::New(data, end - start); //将char* 转为Local<string>return scope.Close(string);}
然后可以参考buffer的构造函数来追踪slice的创建// slice(start, end)
Buffer.prototype.slice = function(start, end) {
var len = this.length; //合法性验证
start = clamp(start, len, 0); //clamp函数也是做合法性验证的,会返回合适的start和end值
end = clamp(end, len, len);
return new Buffer(this.parent, end - start, start + this.offset); //最后slice是依靠重新创建一个buffer实例来完成剪切工作的
};
var string,string2,string3;
var bufstr,bufstr2,bufstr3;
var j;
console.time('write 100 string')
for(j=0;j<1000;j++){
var x = j+'';
string += x;
}
console.timeEnd('write 100 string')
console.time('write 100 buffer')
bufstr = new Buffer(100)
for(j=0;j<1000;j++){
var x = j+'';
bufstr.write(x,j);
}
console.timeEnd('write 100 buffer')
console.time('write 100000 string')
for(j=0;j<100000;j++){
var x = j+'';
string2 += x;
}
console.timeEnd('write 100000 string')
console.time('write 100000 buffer')
bufstr2 = new Buffer(100000)
for(j=0;j<100000;j++){
var x = j+'';
bufstr2.write(x,j);
}
console.timeEnd('write 100000 buffer')
console.time('write 1024*1024*10 string')
for(j=0;j<1024*1024*10;j++){
var x = j+'';
string3 += x;
}
console.timeEnd('write 1024*1024*10 string')
console.time('write 1024*1024*10 buffer')
bufstr3 = new Buffer(1024*1024*10)
for(j=0;j<1024*1024*10;j++){
var x = j+'';
bufstr3.write(x,j);
}
console.timeEnd('write 1024*1024*10 buffer')
读取速度都不需要测试了,肯定string更快,buffer还需要toString()的操作。write 100 string: 0ms
write 100 buffer: 6ms
write 100000 string: 37ms
write 100000 buffer: 150ms
write 1024*1024*10 string: 4262ms
write 1024*1024*10 buffer: 8904ms
下面我们比较一下两者的性能区别:var http = require('http');
http.createServer(function (req, res) {
var body = '';
req.on('data',function(chunk){
//console.log(Buffer.isBuffer(chunk))
body +=chunk
})
req.on('end',function(){
console.log(body)
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
})
}).listen(8124);
console.log('Server running at http://127.0.0.1:8124/');
输出结果:var buf = new Buffer('nodejsv0.10.4&nodejsv0.10.4&nodejsv0.10.4&nodejsv0.10.4&');
console.time('string += buf')
var s = '';
for(var i=0;i<10000;i++){
s += buf;
}
s;
console.timeEnd('string += buf')
console.time('buf concat')
var list = [];
var len=0;
for(var i=0;i<10000;i++){
list.push(buf);
len += buf.length;
}
var s2 = Buffer.concat(list, len).toString();
console.timeEnd('buf concat')
在1000次拼接过程中,两者的性能几乎相差一倍,而且当客户上传的是非UTF8的字符串时,直接+=还容易出现错误。string += buf: 15ms
buf concat: 8ms