javascript中循环和CPS循环的性能非常奇怪
为了查看实现循环的continuations-passing样式是否太慢而无法在javascript中使用,我创建了一个JS Perf,用以下代码测试这一点:javascript中循环和CPS循环的性能非常奇怪,javascript,performance,loops,continuations,Javascript,Performance,Loops,Continuations,为了查看实现循环的continuations-passing样式是否太慢而无法在javascript中使用,我创建了一个JS Perf,用以下代码测试这一点: const ITERATIONS = 10000; function NormalLoop() { for (var i = 0; i < ITERATIONS; i++) { console.log("loop iteration"); if (i % 5) {
const ITERATIONS = 10000;
function NormalLoop() {
for (var i = 0; i < ITERATIONS; i++) {
console.log("loop iteration");
if (i % 5) {
console.log("continuing");
i += 2;
continue;
}
console.log("normally going out");
}
console.log("ended loop");
}
function WhileTrueLoop() {
var i = 0;
while (true) {
if (i >= ITERATIONS) {
break;
}
console.log("loop iteration");
if (i % 5) {
console.log("continuing");
i += 2;
i++;
continue;
}
console.log("normally going out");
i++;
}
console.log("ended loop");
}
function NonTrampLoop() {
var i = 0;
n1(i);
}
function n1(i) {
if (i >= ITERATIONS) {
n4(i);
return;
}
console.log("loop iteration");
if (i % 5) {
console.log("continuing");
i += 2;
n3(i)
return;
}
n2(i)
}
function n2(i) {
console.log("normally going out");
n3(i);
}
function n3(i) {
i = i + 1;
n1(i);
}
function n4() {
console.log("ended loop");
}
function TrampolineSimplistic() {
var f = function () { return ts1(0) };
while (f !== null) { f = f(); }
console.log("ended loop");
}
function ts1(i) {
if (i >= ITERATIONS) {
return null;
}
console.log("loop iteration");
if (i % 5) {
console.log("continuing");
i += 2;
return function () { return ts3(i); };
}
return function () { return ts2(i); };
}
function ts2(i) {
console.log("normally going out");
return function () { return ts3(i); }
}
function ts3(i) {
i = i + 1;
return function () { return ts1(i); }
}
function TrampolineStreamlined() {
var f = { cont: t1, i: 0 };
while (f.cont !== null) { f.cont(f); }
console.log("ended loop");
}
function t1(th) {
var i = th.i;
if (i >= ITERATIONS) {
th.cont = null;
return;
}
console.log("loop iteration");
if (i % 5) {
i = i + 2;
th.i = i;
th.cont = t3;
return;
}
th.i = i;
th.cont = t2;
return;
}
function t2(th) {
var i = th.i;
console.log("normally going out");
th.i = i;
th.cont = t3;
return;
}
function t3(th) {
var i = th.i;
i = i + 1;
th.i = i;
th.cont = t1;
return;
}
const迭代次数=10000;
函数NormalLoop(){
对于(var i=0;i=迭代次数){
打破
}
log(“循环迭代”);
如果(i%5){
控制台日志(“继续”);
i+=2;
i++;
继续;
}
控制台日志(“正常外出”);
i++;
}
console.log(“结束循环”);
}
函数循环(){
var i=0;
n1(i);
}
功能n1(i){
如果(i>=迭代次数){
n4(i);
返回;
}
log(“循环迭代”);
如果(i%5){
控制台日志(“继续”);
i+=2;
n3(i)
返回;
}
n2(i)
}
功能n2(i){
控制台日志(“正常外出”);
n3(i);
}
功能n3(i){
i=i+1;
n1(i);
}
函数n4(){
console.log(“结束循环”);
}
函数蹦床implicistic(){
var f=function(){returnts1(0)};
而(f!==null){f=f();}
console.log(“结束循环”);
}
功能ts1(i){
如果(i>=迭代次数){
返回null;
}
log(“循环迭代”);
如果(i%5){
控制台日志(“继续”);
i+=2;
返回函数(){returnts3(i);};
}
返回函数(){returnts2(i);};
}
功能ts2(i){
控制台日志(“正常外出”);
返回函数(){returnts3(i);}
}
功能ts3(i){
i=i+1;
返回函数(){returnts1(i);}
}
功能蹦床{
var f={cont:t1,i:0};
而(f.cont!==null){f.cont(f);}
console.log(“结束循环”);
}
功能t1(th){
var i=th.i;
如果(i>=迭代次数){
th.cont=null;
返回;
}
log(“循环迭代”);
如果(i%5){
i=i+2;
th.i=i;
th.cont=t3;
返回;
}
th.i=i;
th.cont=t2;
返回;
}
功能t2(th){
var i=th.i;
控制台日志(“正常外出”);
th.i=i;
th.cont=t3;
返回;
}
功能t3(th){
var i=th.i;
i=i+1;
th.i=i;
th.cont=t1;
返回;
}
这五种方法是使用标准for循环、while true循环、使用朴素函数调用、使用trampoling和CPS以及使用trampoling和CPS在堆上预分配局部变量
我预计for循环最快,紧随其后的是while-true循环,然后蹦床循环比for循环长2-10倍,而naive函数循环比for循环长10-100倍
现在令人震惊的是,蹦床循环在firefox上的表现似乎最快。最慢的循环似乎是while-true循环!即使是简单的函数调用循环也相对较快。当朴素函数循环将堆栈按迭代次数成比例增长,而其他方法使用恒定的堆栈空间时,这怎么可能呢
此外,NaiveTrampoline循环在每次执行期间多次在堆上分配函数。javascript引擎在优化函数调用方面是否过于激进?我是否在代码中做了一些异常愚蠢的事情?答案不是,但我在一些浏览器上运行了一些计时。时间以毫秒为单位,迭代次数取决于浏览器中粗略的最大大小,然后才对堆栈大小产生错误
Firefox
Iterations : 30000
NormalLoop : 0
WhileTrueLoop : 1
NonTrampLoop : 22
TrampSimplistic : 2
TrampStreamlined: 1
Chrome
Iterations : 14000
NormalLoop : 3
WhileTrueLoop : 2
NonTrampLoop : 1
TrampSimplistic : 7
TrampStreamlined: 3
Edge
Iterations : 5000
NormalLoop : 0
WhileTrueLoop : 1
NonTrampLoop : 3
TrampSimplistic : 11
TrampStreamlined: 3
Chrome
Iterations : 200000
NormalLoop : 4
WhileTrueLoop : 4
TrampSimplistic : 68
TrampStreamlined: 14
Firefox中的时间非常一致,对于其他浏览器,结果各不相同,我使用了我认为最一致的输出。hmm我认为我的浏览器在某种程度上在JSPerf中一定很奇怪。Edge和Firefox满足了我的期望,但chrome是完全奇怪的。为什么非铬合金的性能这么好?时间很短,所以我认为你不应该对这些铬的值得出明确的结论。为了获得更好的测试结果,迭代次数应该更多,但它会导致14000以上的堆栈溢出错误。如果删除非循环,其他方法都不会堆栈溢出。这样做,结果将添加到答案中。