zoukankan      html  css  js  c++  java
  • 局部性原理

       局部性原理: CPU访问存储器时,无论是存取指令还是存取数据,所访问的存储单元都趋于聚集在一个较小的连续区域中。

    计算机存储结构内存,一级缓存,二级缓存,寄存器等。缓存是用来存放从内存中取出的指令和数据,用来提高cpu访问内存的速度 
    而寄存器是用来存放cpu在执行指令时所需要的操作数或执行结果寄存器的内容可以通过编程控制,也就是说对程序员而言是可见的,而缓存不能通过编程控制,对程序员而言是透明的。缓存的访问速度是远远快于内存的,计算机执行运算时总是把用到内存的相关的数据放到缓存中以便于下次用到时直接读取缓存数据,缓存只能存放小部分数据,而且缓存的数据也不可能百分百命中,如果缓存不命中,那么CPU 只能从内存再次读取数据。所以提高程序的局部性,对于加快程序的执行速度有帮助的。
    二位数组在内存中是以线性存放,以下就是int[5,4]  myArray的数组内容如下
    0, 0,   0  ,0
    1,  1,1 , 1
    2,2,  2,  2
    3,  3,  3,  3 
    4,  4,  4,  4
    它在内存中是以以下方式存放的:
    0, 0,   0  ,0  1,  1,1 , 1  ,2,2,  2,  2  ,3,  3,  3,  3   ,4,  4,  4,  4
    如果计算数组myArray所有元素之和,有两种方式:
    1 按行依次访问myArray 数组元素,并依次求和
    2 按列依次访问myArray数组元素,并依次求个
    这两种方式在性能上有区别吗?为什么
    答案:有区别,按行访问数组元素求和总是快于按列访问数组元素的求和。
    请看如下代码:
    using System;
    
    using System.Collections.Generic;
    
    using System.Linq;
    
    using System.Text;
    
    using System.Diagnostics;
    
    using System.Threading;
    
    namespace hbb0b0.dotnetTrace
    
    {
    
        class Program
    
        {
    
            static void Main(string[] args)
    
            {
    
                Stopwatch watch = new Stopwatch();
    
                string content = string.Format ("Main: at:{0}",DateTime.Now);
    
                Trace.WriteLine(content);
    
                watch.Start();
    
               
    
                NumberTest numberTest = new NumberTest();
    
                for (int i = 0; i < 5;i++ )
    
                {
    
                    //按行方式求和
    
                    numberTest.CalcByRowFirst();
    
                    //按列方式求和
    
                    numberTest.CalcByColumnFirst();
    
                }
    
                watch.Stop();
    
                //统计总的代码的执行时间
    
                content = string.Format("Main cost:{0}", watch.ElapsedMilliseconds);
    
                Trace.WriteLine(content);
    
                Console.Read();
    
            }
    
     
    
        }
    
        class NumberTest
    
        {
    
            //测试数组9000*9000的数组
    
            private int[,] m_intarray = new int[9000, 9000];
    
            //初始化数据
    
            public NumberTest()
    
            {
    
                string content = string.Format("NumberTest time:{0} GetUpperBound(0):{1} GetUpperBound(1):{2}", DateTime.Now.ToString(), m_intarray.GetUpperBound(0), m_intarray.GetUpperBound(1));
    
              Trace.WriteLine(content);
    
              Trace.WriteLine("init data");
    
                for (int i = 0; i <= m_intarray.GetUpperBound(0); i++)
    
                {
    
                    for (int j = 0; j <= m_intarray.GetUpperBound(1); j++)
    
                    {
    
                        m_intarray[i, j] = i + j;
    
                    }
    
                }
    
            }
    
     
    
            /// <summary>
    
            /// 按行优先方式求和数组
    
            /// </summary>
    
            public void CalcByRowFirst()
    
            {
    
                Stopwatch watch = new Stopwatch();
    
               
    
                watch.Start();
    
                long result = 0;
    
                for (int i = 0; i < m_intarray.GetUpperBound(0); i++)
    
                {
    
                    for (int j = 0; j < m_intarray.GetUpperBound(1); j++)
    
                    {
    
                        result += m_intarray[i, j];
    
                    }
    
                }
    
                watch.Stop();
    
                //统计代码的执行时间
    
                string content = string.Format("CalcByRowFirst:Cost:{0} result:{1}", watch.ElapsedMilliseconds, result);
    
                Trace.WriteLine(content);
    
               
    
     
    
            }
    
     
    
     
    
            /// <summary>
    
            /// 按列优先方式求和数组
    
            /// </summary>
    
            public void CalcByColumnFirst()
    
            {
    
                Stopwatch watch = new Stopwatch();
    
                watch.Start();
    
                long result = 0;
    
                for (int i = 0; i < m_intarray.GetUpperBound(1); i++)
    
                {
    
                    for (int j = 0; j < m_intarray.GetUpperBound(0); j++)
    
                    {
    
                        result += m_intarray[j, i];
    
                    }
    
                }
    
                watch.Stop();
    
                //统计代码的执行时间
    
                string content = string.Format("CalcByColumnFirst:Cost:{0} result:{1}", watch.ElapsedMilliseconds, result);
    
                Trace.WriteLine(content);
    
               
    
            }
    
        }
    
    }
     
    App.Config 
    <?xml version="1.0" encoding="utf-8" ?>
    
    <configuration>
    
      <system.diagnostics>
    
        <trace autoflush="true">
    
          <listeners>
    
            <clear/>
    
            <add type="System.Diagnostics.TextWriterTraceListener" initializeData="tracelog" name="txtTrace"></add>
    
            <add type="System.Diagnostics.ConsoleTraceListener" name="ConsoleTrace"></add>
    
          </listeners>
    
        </trace>
    
      </system.diagnostics>
    </configuration>
    

      

     
    输出结果如下:
    Main: at:2013/2/20 11:06:01
    NumberTest time:2013/2/20 11:06:01 GetUpperBound(0):8999 GetUpperBound(1):8999
    init data
    CalcByRowFirst:Cost:3991 result:728676044998
    CalcByColumnFirst:Cost:8264 result:728676044998
    CalcByRowFirst:Cost:4816 result:728676044998
    CalcByColumnFirst:Cost:6969 result:728676044998
    CalcByRowFirst:Cost:4952 result:728676044998
    CalcByColumnFirst:Cost:8203 result:728676044998
    CalcByRowFirst:Cost:5006 result:728676044998
    CalcByColumnFirst:Cost:7134 result:728676044998
    CalcByRowFirst:Cost:4127 result:728676044998
    CalcByColumnFirst:Cost:6388 result:728676044998
    Main cost:62952
    Main: at:2013/2/20 11:09:51
    NumberTest time:2013/2/20 11:09:51 GetUpperBound(0):8999 GetUpperBound(1):8999
    init data
    CalcByRowFirst:Cost:4939 result:728676044998
    CalcByColumnFirst:Cost:7807 result:728676044998
    CalcByRowFirst:Cost:4956 result:728676044998
    CalcByColumnFirst:Cost:8167 result:728676044998
    CalcByRowFirst:Cost:4894 result:728676044998
    CalcByColumnFirst:Cost:7592 result:728676044998
    CalcByRowFirst:Cost:3833 result:728676044998
    CalcByColumnFirst:Cost:7082 result:728676044998
    CalcByRowFirst:Cost:4121 result:728676044998
    CalcByColumnFirst:Cost:8109 result:728676044998
    Main cost:66289
     
    经过多次比对,按行访问数组元素求和总是快于按列访问数组元素的求和
    造成这种情况的原因就是CPU 局部性原理。
    CPU在访问数组元素的时候,总会把他相邻的元素读取出来并放入到缓存中。假设一次访问内存中的数组元素,它会把后续的99个元素放到缓存中,那么CPU每读取
    一次内存就可以减少后续的99次读取内存。
    按行访问的内存读取次数就是
    900*900
    而按列访问内存的读取次数就是
    9000*9000
    按列访问同样会读取一个数组元素后缓存后续的99个数组元素,但是按列求和数组用到的数据并不是缓存的的99个元素,虽然缓存了99个元素,但是后续的99次操作一次缓存
    也不会命中,所以按列访问数组元素求和是会访问内存9000*9000。
     
    所以输出结果中行读取比列读取快也是自然而然的事情。
     
     
  • 相关阅读:
    WebDAV
    招牌老鸭汤(图)-张生记(双菱店)-杭州-大众点评网
    How to install and use Headless Chrome on OSX | Object Partners
    k8s的yaml说明
    config-server-bus动态更新配置
    springboot~maven集成开发里的docker构建
    vue~环境搭建
    logback日志文件位置动态指定
    HDU 4649 Professor Tian(反状态压缩dp,概率)
    android 内部存储 安装apk
  • 原文地址:https://www.cnblogs.com/hbb0b0/p/2919146.html
Copyright © 2011-2022 走看看