使用Linq求和方法Sum计算集合中多个元素和时应该注意的性能问题

来源:互联网 发布:东方财富 for mac 编辑:程序博客网 时间:2024/06/09 19:34

提出问题

本文使用下面的实例来说明问题,以下是实例的完整代码。

//************************************************************    //    // Sum应用示例代码    //    // Author:三五月儿    //     // Date:2014/09/10   //    // http://blog.csdn.net/yl2isoft    //    //************************************************************   using System;using System.Collections.Generic;using System.Diagnostics;using System.Linq; namespace LinqSumExp{    class Program    {        static void Main(string[] args)        {            Console.WriteLine("数据准备中,请稍后...");             List<Score> scoreList = CreateScoreList();             Console.WriteLine("正在执行中,请稍后...");             Stopwatch sw1 = new Stopwatch();            sw1.Start();            //------------代码片段1--------------------start            int mathScoreSum1 = 0;            int chineseScoreSum1 = 0;            int engLishScoreSum1 = 0;            int physicsScoreSum1 = 0;            int chemistryScoreSum1 = 0;            int biologyScoreSum1 = 0;            foreach (var s in scoreList)            {                 mathScoreSum1 += s.MathScore;                chineseScoreSum1 += s.ChineseScore;                engLishScoreSum1 += s.EngLishScore;                physicsScoreSum1 += s.PhysicsScore;                chemistryScoreSum1 += s.ChemistryScore;                biologyScoreSum1 += s.BiologyScore;            }            //------------代码片段1--------------------end            sw1.Stop();            TimeSpan ts1 = sw1.Elapsed;            Console.WriteLine("代码片段1的执行时间为:" + ts1.TotalMilliseconds);             Stopwatch sw2 = new Stopwatch();            sw2.Start();            //------------代码片段2--------------------start            int mathScoreSum2 = 0;            int chineseScoreSum2 = 0;            int engLishScoreSum2 = 0;            int physicsScoreSum2 = 0;            int chemistryScoreSum2 = 0;            int biologyScoreSum2 = 0;            mathScoreSum2 = scoreList.Sum(it => it.MathScore);            chineseScoreSum2 = scoreList.Sum(it => it.ChineseScore);            engLishScoreSum2 = scoreList.Sum(it => it.EngLishScore);            physicsScoreSum2 = scoreList.Sum(it => it.PhysicsScore);            chemistryScoreSum2 = scoreList.Sum(it => it.ChemistryScore);            biologyScoreSum2 = scoreList.Sum(it => it.BiologyScore);            //------------代码片段2--------------------end            sw2.Stop();            TimeSpan ts2 = sw2.Elapsed;            Console.WriteLine("代码片段2的执行时间为:" + ts2.TotalMilliseconds);        }               static List<Score> CreateScoreList()        {            List<Score> scoreList = new List<Score>();            Random rd = new Random();            for (int i = 0; i < 100; i++)            {                Score s = new Score();                s.StudentId = i;                s.StudentName = "s" + i.ToString();                s.MathScore = rd.Next(0, 100);                s.ChineseScore = rd.Next(0, 100);                s.EngLishScore = rd.Next(0, 100);                s.PhysicsScore = rd.Next(0, 100);                s.ChemistryScore = rd.Next(0, 100);                s.BiologyScore = rd.Next(0, 100);                scoreList.Add(s);            }                   return scoreList;        }    }    public class Score    {        public int StudentId { get; set; }        public string StudentName { get; set; }        public int MathScore { get; set; }        public int ChineseScore { get; set; }        public int EngLishScore { get; set; }        public int PhysicsScore { get; set; }        public int ChemistryScore { get; set; }        public int BiologyScore { get; set; }    }}
实例中先定义Score类,使用Score类来保存学生各门功课的成绩,其中属性MathScore、ChineseScore、EngLishScore、PhysicsScore、ChemistryScore、BiologyScore分别用来保存数学、语文、英语、物理、化学、生物的成绩。接着,在CreateScoreList方法中生成包含100个Score对象的集合。最后,使用代码片段1和代码片段2来计算集合中各门功课的总和,其中,代码片段1通过遍历集合的方法来求和,而代码片段2使用Linq的求和方法Sum来实现求和。很显然,两种方法都可以完成求和这个基本功能。但是,在实际开发中,很多时候除了实现基本功能外,还需要考虑其他许多东西,比如性能。那么,这里我就弱弱的问一句:那种方法性能更好?

 

答案揭晓

大家请看黑板。(呵呵,是不是好黑好黑的一块板子啊)

 

图1 程序运行结果图

从程序的执行结果来看,方法1的性能更好。

你可能会说,仅仅通过一次结果无法得出这个结论,因为偶然性。

为了让你心服口服,那我就继续执行,执行,再执行。
经过我n多次重复试验(n到底有多大,你猜),发现:每一次都是方法1耗时更少,方法1性能好于方法2。

为了让我们的实验更具有说服力,增加数据量为1000,10000,100000来执行程序,下面是实验结果:

  • 1000次:方法1--1.2628;方法2--3.3205
  • 10000次:方法1--3.1866;方法2--8.8877
  • 100000次:方法1--15.3749;方法2--65.5758

还是方法1耗时更少吧?

你要是还不服,那我也没办法了,反正我是相信这个结果了。

那么为什么会有这个结果呢?

 

原因说明

查看Linq求和方法Sum的源码,代码如下所示:

public static int Sum(this IEnumerable<int> source){    if (source == null)    {        throw Error.ArgumentNull("source");    }   int num = 0;    foreach (int num2 in source)   {        num += num2;    }    return num;}

很显然,每调用一次Linq的求和方法都会遍历一次集合,所以,方法2会遍历集合5次,而方法1只需遍历集合1次,这就是原因所在。

当然,需要求和的字段越多,数据量越大,两种方法的性能差距将越大。其实,除了在使用Linq的求和方法Sum时会遇见这个问题外,在使用Linq中其他扩展方法时也会遇到这种问题,希望大家以后注意了。

 

 

 

 

 

 

 

0 0
原创粉丝点击