zoukankan      html  css  js  c++  java
  • 性能优化之算法和流程控制

    循环处理是最常见的编程模式之一,也是提升性能必须关注的要点之一。
     
    常见的优化方案有:
     
    ①JavaScript的四种循环(for、do-while、while、for-in)中,for-in循环比其他几种明显要慢。由于每次迭代操作会同时搜索实例或原型属性,for-in循环的每次迭代都会产生更多的开销,所以比其他类型要慢。因此遍历一个属性数量有限的已知属性列表,可以这样优化:
    var props = ['prop1', 'prop2'],i = 0;
    whlie(i < props.length){
       precess(object[props[i++]]);
    }
    该代码只关注给定的属性,减少了循环的开销。
    而对于,for、while、do-while。我在chrome下测试了一下,先创建一个大小为1000000的数组,每项乘100再叠加。
    测试用例:
    window.onload = function(){
    var items  = Array(1000000).join(',').split(',').map(function(item, index) {
       return index;
    });
       console.log(forCircle())
       console.log(whileCircle())
       console.log(doCircle())
    
    function forCircle(){
    console.profile();
    var currTime = new Date();
     var tal = 0; 
        for(var i = 0;i < items.length; i++){
           tal = tal + process(items[i]);
        }
       console.profileEnd();
       console.log('forCircle用时:' + (new Date() - currTime) + 'ms');
        return tal;
    }
    function whileCircle(){
    console.profile();
    var currTime = new Date();
        var tal = 0; 
        var j = 0;
        while (j < items.length){
          tal = tal + process(items[j++]);
        }
       console.profileEnd();
       console.log('whileCircle用时:' + (new Date() - currTime) + 'ms');
        return tal;
    }
    function doCircle(){
    console.profile();
    var currTime = new Date();
       var tal = 0; 
       var k = 0;
        do{
            tal = tal + process(items[k++]);
        }while (k < items.length) 
           console.profileEnd();
       console.log('doCircle用时:' + (new Date() - currTime) + 'ms');
        return tal;
    }
    function process(item){
        return item*100;
    }
    }
    

     取某次测试结果:

       

     

    平均来说,for循环耗时8ms,while耗时4ms,doWhile耗时也是4ms。for是最慢的。

     
    ②减少迭代的工作量。把数组长度保存在局部变量中再遍历、颠倒数组的遍历顺序。
    最常见的一个循环:
    for(var i = 0;i < items.length; i++){
       process(items[i]);
    }
    //
    var j = 0;
    while (j < items.length){
      process(items[j++]);
    }
    //
    var k = 0;
    do{
        process(items[k++]);
    }while (k < items.length)
    

    在这个循环中,每次运行都会产生如下操作:

    ①查找一次属性(items.length)

    ②执行数值比较一次(i < items.length) 

    ③查看控制条件是否为true(i < items.length ==true) 

    ④一次自增操作(i++)

    ⑤一次数组查找(items[i])

    ⑥一次函数调用(process(items[i]))

    若把数组长度存到一个局部变量,那么就不需要每次都查找一次items.length,也就提高了性能。

    改为这样:

    for(var i = 0, len = items.length;i < len; i++){
       process(items[i]);
    }
    //
    var j = 0,
    count = items.length;
    while (j < count){
      process(items[j++]);
    }
    //
    var k = 0,
    num = items.length;
    do{
        process(items[k++]);
    }while (k < num)
    

      这样在大多数浏览器中能节省大概25%的运行时间(IE中甚至可以节省50%)。总的来说,循环次数大的情况下,运行时间确实有提升。取某次结果如下:

     没有局部存量存储数组长度时:

     

     有局部变量存储数组长度时:

    ③减少迭代次数,“Duffs Device”即“达夫设备“循环体展开技术。适合于迭代次数较大的情况下。
    摘抄一下书中达夫设备的基本理念:每次循环中最多可 8 次调用 process()函数。循环迭代次数为元素总数除以8。 因为总数不一定是 8的整数倍, 所以 startAt 变量存放余数, 指出第一次循环中应当执行多少次 process()。比方说现在有 12 个元素,那么第一次循环将调用 process()4次,第二次循环调用 process()8 次,用 2 次循环代替了 12次循环。
    基本模式:
    var iterations = Math.floor(items.length/8),  
        startAt = items.length%8,  
        i = 0;  
    do{  
        switch(startAt){  
            case 0 : process(items[i++]);  
            case 7 : process(items[i++]);  
            case 6 : process(items[i++]);  
            case 5 : process(items[i++]);  
            case 4 : process(items[i++]);  
            case 3 : process(items[i++]);  
            case 2 : process(items[i++]);  
            case 1 : process(items[i++]);  
        }  
        startAt =  0;  
     }while(--iterations);  
    

      

    ④基于函数的迭代比基于循环的迭代消耗性能更多。例:for循环迭代与forEach函数迭代。
     
    ⑤优化if-else,通常来说,switch比if-else快,但是在判断条件较多时,使用查找表比if-else和switch都快。
     
    更多测试结论,可参考:http://www.cnblogs.com/hmking/archive/2011/10/10/2205321.html
    更多学习可参考《高性能JavaScript》
     
     
  • 相关阅读:
    Wooden Sticks(hdu1051)
    Leftmost Digit(hdu1060)(数学题)
    Sum of Remainders(数学题)
    Brain Network (medium)(DFS)
    Brain Network (easy)(并查集水题)
    Collective Mindsets (medium) (逻辑题)
    Collective Mindsets (easy)(逻辑题)
    RMQ with Shifts(线段树)
    Throwing Dice(概率dp)
    圆桌会议
  • 原文地址:https://www.cnblogs.com/LuckyWinty/p/6381970.html
Copyright © 2011-2022 走看看