zoukankan      html  css  js  c++  java
  • 使用Linq求和方法Sum计算集合中多个元素和时应该注意的性能问题

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

    三五月儿 2014-09-10 22:40:31 21633 收藏 2
    分类专栏: C# 文章标签: Linq Sum Linq性能 Linq求和
    版权
    提出问题

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

    //************************************************************
    //
    // 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中其他扩展方法时也会遇到这种问题,希望大家以后注意了。

     
    ————————————————
    版权声明:本文为CSDN博主「三五月儿」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/yl2isoft/article/details/39188641

    1.你好?是因為你,身邊的人好。—— by潇沫明月 -dont't repeat yourself 2.下辈子 无论 爱与不爱 我们 都不会 再见 3.有所见略同的对手 有对酒当歌的友人 有真心相对的红颜 有识千里马的伯乐 有一颗炽烈真诚的心 所以----- 要知道你最想做的 i will not repeat myself
  • 相关阅读:
    为什么button在设置标题时要用一个方法,而不像lable一样直接用一个属性
    桥接模式(透传模式)和直驱模式
    vb.net版机房收费系统——教你七层架构(三)—外观模式
    Android 4.4 KitKat NotificationManagerService使用具体解释与原理分析(二)__原理分析
    poj-2758 Checking the Text
    一种感悟,为什么努力了确还是死了一地
    一位程序员的6年总结(转)
    主键生成策略
    Linux下的crontab定时执行任务命令详解
    win7 64下安装mysql-python报错的解决办法
  • 原文地址:https://www.cnblogs.com/kissy/p/14626938.html
Copyright © 2011-2022 走看看