凤头
几天前,我在纠结以后开发究竟要使用Safari还是Chrome的时候,发现了一篇文章:
用最简单易懂的道理告诉你,为什么JavaScript在现代引擎(V8,JavaScriptCore)下,能表现出卓越性能!
文章中使用斐波拉切递归算法测试了浏览器的性能,其代码如下:
let num = 40;
let startDate = new Date().getTime();
let result = logfs(num);
let endDate = new Date().getTime();
console.log("time:" + ((endDate - startDate) / 1000) + "s", "result:" + result);
function logfs(num) {
let rsString = "";
for (let i = 1; i <= num; i++) {
let rs = fs(i);
if (i === 1) {
rsString = rsString + rs;
} else {
rsString = rsString + "," + rs;
}
console.log(rs);
}
return rsString;
function fs(n) {
if (n <= 2) {
return 1;
} else {
return fs(n - 1) + fs(n - 2);
}
}
}
我也简单的在Safari和Chrome中测试了一下,计算40项,在Chrome中大概需要3.5s,在Safari中大概需要2.5s。
计算个兔子数列竟然需要这么久,于是就引出了我对斐波拉切数列算法的优化。
猪肚
使用数组优化算法
对于优化,我首先想到的是抛弃递归,转而使用一个数组存储每次的结果,代码如下:
let num = 40;
let res = [];
function main(num) {
for (let i = 0; i < num; i++) {
if (i <= 2) {
res [i] = 1;
}else {
res [i] = res[i - 1] + res[i - 2];
}
console.log(res[i]);
}
}
let startDate = new Date().getTime();
main(num);
let endDate = new Date().getTime();
console.log("time:" + ((endDate - startDate) / 1000) + "s", "result:" + res);
经测试,计算40项,其时间开销大概在0.015s左右;计算400项,其时间开销大概在0.085s左右。
memoization方案优化算法
使用数组计算的这个结果,大概还能让我满意,但总觉得还是有些慢,于是我发现了这样一篇文章:
斐波那契数列求和的js方案以及优化
文中介绍了多种优化方案,我最感兴趣的是其中的使用 memoization方案
优化递归。
仿照他的方案,我简单写了一下,代码如下:
let fibonacci = (function () {
let memory = {};
return function (n) {
if (n === 0 || n === 1) {
return n;
}
if (memory[n - 2] === undefined) {
memory[n - 2] = fibonacci(n - 2)
}
if (memory[n - 1] === undefined) {
memory[n - 1] = fibonacci(n - 1)
}
return memory[n] = memory[n - 1] + memory[n - 2]
}
})();
function speedTest(n) {
let startDate = new Date().getTime();
let mem = fibonacci(n);
let endDate = new Date().getTime();
console.log("time:" + ((endDate - startDate) / 1000) + "s", mem);
}
speedTest(40);
结果发现这次计算40项和计算400项,时间基本为0,偶尔一次0.001s。
这个时间就很舒服了。
还有什么原因影响了性能?
细心的我发现,数组的方式打印出了每次计算的结果,而memoization方案没有打印。所以,console.log()
会不会是影响性能的原因呢?
于是我去掉了数组方案中的console.log()
,代码如下:
let num = 400;
let res = [];
function main(num) {
for (let i = 0; i < num; i++) {
if (i <= 2) {
res [i] = 1;
}else {
res [i] = res[i - 1] + res[i - 2];
}
// console.log(res[i]);
}
}
let startDate = new Date().getTime();
main(num);
let endDate = new Date().getTime();
console.log("time:" + ((endDate - startDate) / 1000) + "s", "result:" + res);
结果,无论是计算40项还是计算400项,其时间开销和memoization方案一样:基本为0s,偶尔一次0.001s 。
果然是console.log()
影响力性能!
神仙打架
为了比较 memoization方案 和 数组方案的性能差异,进行了如下实验:
//TODO
豹尾
//TODO