zoukankan      html  css  js  c++  java
  • 嵌套For循环性能优化案例

    1 案例描述

    某日,在JavaEye上看到一道面试题,题目是这样的:请对以下的代码进行优化

    for (int i = 0; i < 1000; i++)
        for (int j = 0; j < 100; j++)
            for (int k = 0; k < 10; k++)
                testFunction (i, j, k);

    2 案例分析

    从给出的代码可知,不论如何优化,testFunction执行的次数都是相同的,该部分不存在优化的可能。那么,代码的优化只能从循环变量i、j、k的实例化、初始化、比较、自增等方面的耗时上进行分析。
    首先,我们先分析原题代码循环变量在实例化、初始化、比较、自增等方面的耗时情况: 

    变量 实例化(次数) 初始化(次数) 比较(次数) 自增(次数)
    i 1 1 1000 1000
    j 1000 1000 1000 * 100 1000 * 100
    k 1000 * 100 1000 * 100 1000 * 100 * 10 1000 * 100 * 10

    该代码的性能优化就是尽可能减少循环变量i、j、k的实例化、初始化、比较、自增的次数,同时,不能引进其它可能的运算耗时。 

    3 解决过程

    从案例分析,对于原题代码,我们提出有两种优化方案:

    方案一:

    for (int i = 0; i < 10; i++)  
        for (int j = 0; j < 100; j++)  
            for (int k = 0; k < 1000; k++)  
                testFunction (k, j, i); 

    该方案主要是将循环次数最少的放到外面,循环次数最多的放里面,这样可以最大程度的(注:3个不同次数的循环变量共有6种排列组合情况,此种组合为最优)减少相关循环变量的实例化次数、初始化次数、比较次数、自增次数,方案耗时情况如下:

    变量 实例化(次数) 初始化(次数) 比较(次数) 自增(次数)
    i 1 1 10 10
    j 10 10 10 * 100 10 * 100
    k 10 * 100 10 * 100 10 * 100 * 1000 10 * 100 * 1000

    方案二:

    int i, j, k;  
        for (i = 0; i < 10; i++)  
            for (j = 0; j < 100; j++)  
                for (k = 0; k < 1000; k++)  
                    testFunction (k, j, i); 

    该方案在方案一的基础上,将循环变量的实例化放到循环外,这样可以进一步减少相关循环变量的实例化次数,方案耗时情况如下:

    变量 实例化(次数) 初始化(次数) 比较(次数) 自增(次数)
    i 1 1 10 10
    j 1 10 10 * 100 10 * 100
    k 1 10 * 100 10 * 100 * 1000 10 * 100 * 1000

     4 解决结果

    那么,提出的优化方案是否如我们分析的那样有了性能上的提升了呢?我们编写一些测试代码进行验证,数据更能说明我们的优化效果。

    测试代码:

    为了让效果更明显,加大了循环次数。

    public class LoopOptimizeDemo
    {
        public static void main(String[] args){
            testA();
            testB();
            testC();
        }
        
        public static void testA(){ // 未优化前
            long start = System.nanoTime();
            for(int i = 0; i < 10000; i++)
                for(int j = 0; j < 1000; j++)
                    for(int k = 0; k < 10; k++)
                        ;
            System.out.println("testA time>>"+(System.nanoTime()-start)+"ns");
        }
    
        public static void testB(){ // 方案一
            long start = System.nanoTime();
            for(int i = 0; i < 10; i++)
                for(int j = 0; j < 1000; j++)
                    for(int k = 0; k < 10000; k++)
                        ;
            System.out.println("testB time>>"+(System.nanoTime()-start)+"ns");
        }
        
        public static void testC(){ // 方案二
            long start = System.nanoTime();
            int i, j, k;
            for(i = 0; i < 10; i++)
                for(j = 0; j < 1000; j++)
                    for(k = 0; k < 10000; k++)
                        ;
            System.out.println("testC time>>"+(System.nanoTime()-start)+"ns");
        }
    }
    ---------- 运行Java ----------
    testA time>>9970757ns
    testB time>>6865587ns
    testC time>>6221953ns
    
    输出完成 (耗时 0 秒) - 正常终止

    从上面的测试结果来看,优化后的方案明显性能优于原方案,达到了优化的效果。测试机器的配置不同,结果可能会不同;循环次数越大,效果越明显,各位看官请自行测试。

    5 总结

    从案例分析和解决过程中的三个表的分析可知,优化方案一和优化方案二的性能都比原代码的性能好,其中优化方案二的性能是最好的。在嵌套For循环中,将循环次数多的循环放在内侧,循环次数少的循环放在外侧,其性能会提高;减少循环变量的实例化,其性能也会提高。从测试数据可知,对于两种优化方案,如果在循环次数较少的情况下,其运行效果区别不大;但在循环次数较多的情况下,其效果就比较明显了。  

  • 相关阅读:
    Combine 框架,从0到1 —— 4.在 Combine 中使用计时器
    Combine 框架,从0到1 —— 4.在 Combine 中使用通知
    Combine 框架,从0到1 —— 3.使用 Subscriber 控制发布速度
    Combine 框架,从0到1 —— 2.通过 ConnectablePublisher 控制何时发布
    使用 Swift Package Manager 集成依赖库
    iOS 高效灵活地配置可复用视图组件的主题
    构建个人博客网站(基于Python Flask)
    Swift dynamic关键字
    Swift @objcMembers
    仅用递归函数操作逆序一个栈(Swift 4)
  • 原文地址:https://www.cnblogs.com/zoe15/p/5350720.html
Copyright © 2011-2022 走看看