数据结构和算法之C#

来源:互联网 发布:iphone蜂窝数据3g 编辑:程序博客网 时间:2024/05/01 02:27

      最近看了一本书,有关数据结构和算法在C#中的应用问题,其中不乏涉及到性能的探讨,以前写程序代码,很少去关注代码的执行效率和性能,功能完备了就算了事了。最近觉得有必要去重新认识下自己写的代码质量有多高。

      该书并非纯理论的讲解一些枯燥的概念,而是从简单的实用技巧阐述了一些很实际要关注的问题,我就其中时间测试来讲解下其中的奥妙。

      首先测试 我们需要自己准备一段代码。我就拿下面代码做实验。

static void DisplayNums(int[] arr){        for (int i=0;i<arr.GetUpperBound(0);i++)        Console.Write(arr[i] + " ");}

  一般接下来,大家可能就想,需要一个变量,把子程序调用时的系统时间赋值给此变量。此外还需要一个变量来存储子程序返回时的时间,根据这些描述,我们写下这段代码:

DateTime startTime;TimeSpan endTIme;startTime = Datetime.Now;endTime  = DateTime.Now.Subtract(startTIme);

  有了这些,好我们开始测试。我把整段测试代码贴出来。

View Code
 1 using System; 2 using System.Diagnostics; 3 class chapter1 4 { 5        static void Main() 6        { 7                 int[] nums = new int[100000]; 8                 BuildArray(nums); 9                 DateTime startTime;10                 TimeSpan endTime;11                 startTime = Datetime.Now;12                 DisplayNums(nums);13                 DisplayNums(nums);14                 DisplayNums(nums);15                 endTime = Datetime.Now.Subtract(startTime);16                Console.WriteLine("Time:"+duration.TotalSeconds);17        }18         static void BuildArray(int[] arr)19         {20                 for( int i =0;i<=99999;i++)21                           arr[i]=i;22         }23         static void DisplayNums(int[] arr)24          {25                 for(int i=0;i<=arr.GetUpperBound(0);i++)26                           Console.Write(arr[i] + " ");27          }28 }

  测试结果在我本机是33~35秒之间,每次测试不一样。大家可能认为已经Ok了,其实没有考虑测试环境,在.Net 环境中运行时间代码是完全不合适的。Why?

     首先,代码测试的是从子程序调用开始到子程序返回主程序之间所有的时间。但是测试所测量的时间也包含了与C#程序同时运行的其他进程所用的时间。

     其次,时间代码没有考虑.Net环境下执行的无用单元收集。在类似.Net 这样的运行时间环境中,系统可能在执行无用单元收集的任何一个时间暂停,时间代码没有考虑无用单元收集。结果时间很容易受到无用单元收集的影响(无用单元收集就是指的垃圾收集或垃圾回收)。How to do?

     我们必须考虑这些情况。先来看如何处理无用单元收集。无用单元收集用来释放在子程序中不需要再用的变量,当没有引用堆数据的行为时,只有通过无用单元收集才可以移除这些数据,那我们必须确保在执行时间测试时没有运行无用单元收集器。这个可以通过强制调用无用单元收集器来进行专门的无用单元收集。为此.Net环境提供了专门的对象==GC。  

      GC.Colllect();

     但并不是所有都要这样做的。存储在堆中的每一个对象都有一个称为finalizer的专门方法。finalizer方法是在删除对象之前执行的最后一步。有关finalizer方法的问题是,这些方法不是按照系统化方式运行的。无法确定起是否真的执行了,为了确定这一点,我们添加一行代码来告诉程序等待堆上对象的所有finalizer方法都运行后再继续。此代码行如下:

     GC.WaitForPendingFinalizers();

至此 这个障碍已经清除了。现在就是要采用正确的线程。在.Net 环境中,程序都运行在被成为 应用程序域的进程中。这就允许在同一时间内分开运行每个不同的程序,在对代码进行时间测试时,需要确保正在进行时间测试的代码只在为自身程序分配的进程中,而不是操作系统执行的其他任务里。

     Process类可以做到这一点。Process拥有的方法允许选取当前的进程(程序运行其内的进程)、选取程序运行其内的线程,以及选取存储线程开始执行时间的计时器。看代码。

    TimeSpan startTime;

     startingTime = Process.GetCurrentProcess().Threads[0].UserProcessorTime;

     捕获停止时间。

     duration =Process.GetCurrentProess().Threads[0].UserProcessorTime.Subtract(startingTime);

程序如上,再改动下原先的代码 ,我们会发现测试的时间 有显著的差异。因而在.NET 环境中的时间测试应该使用.NET 方法来做。上面的代码可以重写为一个Timing Test 类。以后就可以方便用来测试代码的是时间。

原创粉丝点击