首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Javascript中的执行时间不一致

Javascript中的执行时间不一致
EN

Stack Overflow用户
提问于 2013-07-11 08:23:41
回答 1查看 132关注 0票数 1

注:如果我可以的话,我会检查Mike Brandt的答案,因为他发现了我在死/活像素比率上的愚蠢错误。但是Ken得到了普遍的好建议的认可。

我试图在Canvas元素中调试Conway的生命游戏的一些性能问题,我得到了一些非常奇怪的性能问题。

我得到了大约4-12FPS和绘图功能的基准测试表明,整体性能应该能够上升到60FPS。

下面是画布绘制代码。RequestAnimationFrame以大约30FPS的速度调用updateBgCanvas。整个过程都在Chrome 28.0.1500.70上运行和性能测试。

(我为混乱的代码道歉,我一直在将代码分解成更小的子单元,以便在性能分析器中获得更大的粒度,而没有太多考虑好的编码技术)

毫不奇怪,画布绘制函数(fillDead和fillLive是最大的CPU占用率,但在这里它变得奇怪。fillLive消耗了5-6%的CPU时间(大约是我在fillRect基准测试中所期望的),而fillDead消耗了36-38%的CPU时间。除了对1或0进行条件测试之外,这些都是相同的函数。

我已经尝试在父函数中交换调用顺序,并且用于填充和fillDead的颜色的调用时间始终是几乎相同的fillLive的6-7倍。我完全不知道为什么会这样。

有什么建议吗?

代码语言:javascript
复制
  window.bgVars = {
     "about": "The background is the famous Conway Game of Life",
     "_Canvas": {},
     "_Ctx": {},
     "xBlockSize": 5,
     "yBlockSize": 5,
     "xBlocks": 0,
     "yBlocks": 0,
     "bornVals": [3],
     "stayAliveVals": [2, 3],
     "cGrid": [],
     "cGrid2": [],
     "cL": 0,
     "initBgVars" : function(iCanvas, iCtx){
        console.log(this.xBlockSize);
        this._Canvas = iCanvas;
        this._Ctx = iCtx;
        this.cGrid = [];
        this.cGrid2 = [];
        this.xBlocks = Math.round(myCanvas.width/this.xBlockSize) + 1;
        this.yBlocks = Math.round(myCanvas.height/this.yBlockSize) + 1;
        for(var rep=0;rep<(this.xBlocks * this.yBlocks);rep++){
           this.cGrid.push(Math.round(Math.random()*0.8));
        }
        this.cGrid2.length = this.cGrid.length;
     },
     "cirInd": function(index){
        //returns modulus, array-wrapping value to implement circular array
        if(index<0){index+=this.cGrid.length;}
        return index%this.cGrid.length;
     },
     "calcNeighbors": function(rep){
        var foo = this.xBlocks;
        var neighbors = this.cGrid[this.cirInd(rep-foo-1)] + this.cGrid[this.cirInd(rep-foo)] + this.cGrid[this.cirInd(rep-foo+1)] + this.cGrid[this.cirInd(rep-1)] + this.cGrid[this.cirInd(rep+1)] + this.cGrid[this.cirInd(rep+foo-1)] + this.cGrid[this.cirInd(rep+foo)] + this.cGrid[this.cirInd(rep+foo+1)];
        return neighbors;
     },
     "refreshGrid": function(){
        for(var rep=0;rep<this.cGrid.length;rep++){
           if(Math.random()<0.0002){this.cGrid2[rep] = 1;}
           this.cGrid[rep] = this.cGrid2[rep];
        }
     },
     "lifeRules": function(rep, neighbors){
           if(this.cGrid[rep] == 1){  //stay alive rules
              for(var rep2=0;rep2<this.stayAliveVals.length;rep2++){
                 if(neighbors==this.stayAliveVals[rep2]){this.cGrid2[rep] = 1;}
              }
           }
           if(this.cGrid[rep] == 0){  //'born' rules
              for(var rep2=0;rep2<this.bornVals.length;rep2++){
                 if(neighbors==this.bornVals[rep2]){this.cGrid2[rep] = 1;}
              }
           }          
     },
     "fillDead": function(){
        for(var rep=0;rep<this.cGrid.length;rep++){
           if(this.cGrid[rep] == 0){
              this._Ctx.fillRect((rep%this.xBlocks)*this.xBlockSize, Math.floor(rep/this.xBlocks)*this.yBlockSize, this.xBlockSize, this.yBlockSize);
           }
        }          
     },
     "fillLive": function(){
        for(var rep=0;rep<this.cGrid.length;rep++){
           if(this.cGrid[rep] == 1){
              this._Ctx.fillRect((rep%this.xBlocks)*this.xBlockSize, Math.floor(rep/this.xBlocks)*this.yBlockSize, this.xBlockSize, this.yBlockSize);
           }
        }          
     },
     "updateBgCanvas": function(){
        //fill live squares
        this._Ctx.fillStyle = 'rgb(130, 0, 0)';
        this.fillLive();
        //fill dead squares
        this._Ctx.fillStyle = 'rgb(100, 0, 0)';
        this.fillDead();
        //calculate next generation to buffer
        for(var rep=0;rep<this.cGrid.length;rep++){
           //add up the live squares in the 8 neighbor blocks
           var neighbors = this.calcNeighbors(rep);
           this.cGrid2[rep] = 0;
           //implement GoL ruleset
           this.lifeRules(rep, neighbors);
        }
        //seed with random noise to keep dynamic and copy to display buffer
        this.refreshGrid();
     }
  }

对Ken建议的数学函数进行编辑,将父对象变量复制到本地变量,在数学函数中获得约16%的性能增益,总体性能增益约为4%:

代码语言:javascript
复制
     "cirInd": function(index, mod){
        //returns modulus, array-wrapping value to implement circular array
        if(index<0){index+=mod;}
        return index%mod;
     },
     "calcNeighbors": function(rep){
        var foo = this.xBlocks;
        var grid = this.cGrid;
        var mod = grid.length;
        var neighbors = grid[this.cirInd(rep-foo-1, mod)] + grid[this.cirInd(rep-foo, mod)] + grid[this.cirInd(rep-foo+1, mod)] + grid[this.cirInd(rep-1, mod)] + grid[this.cirInd(rep+1, mod)] + grid[this.cirInd(rep+foo-1, mod)] + grid[this.cirInd(rep+foo, mod)] + grid[this.cirInd(rep+foo+1, mod)];
        return neighbors;
     },
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-07-11 08:54:59

要举例说明如何提高性能,请尝试将fillDead函数替换为以下修改:

代码语言:javascript
复制
"fillDead": function(){

   /// localize to vars so interpreter doesn't
   /// have to walk of the branches all the time:
   var cGrid = this.cGrid, ctx = this._Ctx,
       xBlocks = this.xBlocks, xBlockSize = this.xBlockSize,
       yBlockSize = this.yBlockSize,
       rep = cGrid.length - 1;

   /// while loops are generally faster than for loops
   while(rep--) 
      if(cGrid[rep] == 0){
         ctx.fillRect((rep%xBlocks) * xBlockSize, ((rep/xBlocks)|0) * yBlockSize, xBlockSize, yBlockSize);
      }
   }
},
//...

那会有什么表现呢?如果只有1或2个网格元素,你看不到太大的区别,但网格元素越多,性能就越好(无法测试,因为我没有完整的代码)。

如果您发现它提高了性能,那么您也应该将其应用于其他函数。您还应该看看是否可以将其中一些this.*放入父作用域中的本地var,并将它们作为参数传递给函数。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17583117

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档