我在Node中创建了一个DNS工具,我想知道如何使用bitwise优化toLong()
的性能?我已经包含了一些伪代码供参考。
var _parser = function (ip) {
return ip.split('.').map(function (i) {
return i | 0;
});
},
_isIPv4 = function (ip) {
var i, isValid = true, octets = _parser(ip);
if (octets.length !== 4) {
isValid = false;
}
octets.forEach(function (octet) {
if (octet < 0 || octet > 255) {
isValid = false;
}
});
return isValid;
};
toLong: function (ip) {
var i, converted, octets = _parser(ip);
if (!_isIPv4(ip)) {
throw 'Invalid IPv4 address!';
}
converted = 0;
for (i = 0; i < octets.length; i++) {
converted += octets[i] * Math.pow(256, (3 - i));
}
return converted;
};
答案 0 :(得分:1)
在这里:http://jsperf.com/node-bitwise-calculations-with-ip-addresses
编辑2:这是最初的解决方案,大约是2倍的性能:
var p256 = [Math.pow(256, 3), Math.pow(256, 2), 256, 1];
var cache = {};
var newToLongCache = function(ip) {
var octets = _parser(ip);
var converted = 0;
for (var i = 0; i < octets.length; i++) {
var val = octets[i];
if (cache[val] == null) {
cache[val] = {};
}
if (cache[val][i] == null) {
cache[val][i] = val * p256[i];
}
converted += cache[val][i];
}
return converted;
};
这是更新的展开解决方案,没有按位运算符(相同的5倍性能):
var unrolledMultiplicationLongNoBitwise = function(ip) {
var octets = ip.split('.');
if (octets.length !== 4) throw "Invalid IPv4 address!";
octets[0] = octets[0] | 0;
octets[1] = octets[1] | 0;
octets[2] = octets[2] | 0;
octets[3] = octets[3] | 0;
if ((octets[0] < 0 || octets[0] > 255) ||
(octets[1] < 0 || octets[1] > 255) ||
(octets[2] < 0 || octets[2] > 255) ||
(octets[3] < 0 || octets[3] > 255)) {
throw 'Invalid IPv4 address!';
}
return (octets[0] * 16777216) + (octets[1] * 65536) +
(octets[2] * 256) + octets[3];
};
答案 1 :(得分:1)
我真的建议展开这些循环并放弃函数调用。我在@imsky创建的jsPerf中添加了一个修订版:http://jsperf.com/node-bitwise-calculations-with-ip-addresses/6看起来这比原版快〜5倍。
var unrolledLong = function(ip) {
var octets = ip.split('.');
if (octets.length !== 4) throw "Invalid IPv4 address!";
octets[0] = octets[0] | 0;
octets[1] = octets[1] | 0;
octets[2] = octets[2] | 0;
octets[3] = octets[3] | 0;
if ((octets[0] < 0 || octets[0] > 255) ||
(octets[1] < 0 || octets[1] > 255) ||
(octets[2] < 0 || octets[2] > 255) ||
(octets[3] < 0 || octets[3] > 255)) {
throw 'Invalid IPv4 address!';
}
// The >>> 0 calls will force the number back to an unsigned value.
return octets[3] +
((octets[2] << 8) >>> 0) +
((octets[1] << 16) >>> 0) +
((octets[0] << 24) >>> 0);
};
如果按位数学有点奇怪,你也可以使用乘法:
var unrolledLong = function(ip) {
var octets = ip.split('.');
if (octets.length !== 4) throw "Invalid IPv4 address!";
octets[0] = octets[0] | 0;
octets[1] = octets[1] | 0;
octets[2] = octets[2] | 0;
octets[3] = octets[3] | 0;
if ((octets[0] < 0 || octets[0] > 255) ||
(octets[1] < 0 || octets[1] > 255) ||
(octets[2] < 0 || octets[2] > 255) ||
(octets[3] < 0 || octets[3] > 255)) {
throw 'Invalid IPv4 address!';
}
// The >>> 0 calls will force the number back to an unsigned value.
return octets[3] +
(octets[2] * 0x100) +
(octets[1] * 0x10000) +
(octets[0] * 0x1000000);
};
答案 2 :(得分:1)
只是玩弄优化:
function( ip ){
var octets = ip.split( '.' );
if( ( octets.length !== 4 ) ||
( ( octets[0] |= 0 ) & ~0xFF ) ||
( ( octets[1] |= 0 ) & ~0xFF ) ||
( ( octets[2] |= 0 ) & ~0xFF ) ||
( ( octets[3] |= 0 ) & ~0xFF ) ){
throw new Error( 'Invalid IPv4 address!' );
}
return ( octets[3] ) |
( octets[2] << 8 ) |
( octets[1] << 16 ) |
( octets[0] * 0x1000000 );
}