public static List<Account> GetAccountsA(List<User> users)
        {
            List<Account> accounts = new List<Account>();
            foreach (User item in users)
            {
                if (item.Age > 21 && item.Age < 25)
                {
                    Account account = new Account();
                    account.ID = item.ID;
                    account.Name = item.FirstName + item.SecondName;
                    account.Age = item.Age; accounts.Add(account);
                }
            }
            return accounts;
        }
        public static List<Account> GetAccountsB(List<User> users)
        {
            var result = from item in users
                         where item.Age > 21 && item.Age < 25
                         select new Account
                         {
                             ID = item.ID,
                             Name = item.FirstName + item.SecondName,
                             Age = item.Age
                         };
            return result.ToList<Account>();
        }菜菜的我,用笨拙的方式进行测试,感觉上在效率没有什么差别。可能代码写的“不利于测试”,也可能测试的方式错误。能力有限,故而问之。如果您知道,不妨分享您的心得与见解吧?

解决方案 »

  1.   

    额,忘了说明。
    我测试的Linq,是用于进行数据的筛选。不知道用Linq的效率会低的“离谱”,还是相差无几?
      

  2.   

    这个我也认为开销自然小,“估计”Linq里实际上也是使用foreach
      

  3.   

    LINQ会慢一些,因为where里面会多一个迭代器调用。
      

  4.   

    要慢至少一个数量级.
    循环1千万次
    For循环: 31.0018 ms
    Linq:    977.0559 ms测试代码如下:using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;namespace LinqTest
    {
        class Program
        {
            static void Main(string[] args)
            {
                char[] cs = new char[3] { '1', '2', '3' };
                DateTime BeginTime = DateTime.Now;
                DateTime EndTime;
                for (int i=0; i < 1000000; i++)
                {         
                    ForLoop(cs);
                }
                EndTime = DateTime.Now;
                Console.WriteLine(EndTime.Subtract(BeginTime).TotalMilliseconds.ToString() + " ms");            BeginTime = DateTime.Now;
                for (int i = 0; i < 10000000; i++)
                {
                    LinqSelect(cs);
                }
                EndTime = DateTime.Now;
                Console.WriteLine(EndTime.Subtract(BeginTime).TotalMilliseconds.ToString() + " ms");            Console.ReadKey();
            }        static void ForLoop(char[] cs)
            {
               for (int i = 0; i < cs.Length; i++)
                {
                    if (cs[i] == '2') ; //Console.Write(cs[i]);
                }
            }        static void LinqSelect(char[] cs)
            {
                var o = from c in cs
                        where c == '2'
                        select c;
                foreach (var r in o)
                {
                   // Console.Write(r);
                }
            }
        }
    }
      

  5.   


    我觉得foreach和Linq都是用GetGenerator的吧,所以效率上差不多。
      

  6.   

    以下是:
    static void ForLoop(char[] cs)
    用ldasm 查看其生成的MSIL代码:
    .method private hidebysig static void  ForLoop(char[] cs) cil managed
    {
      // 代码大小       45 (0x2d)
      .maxstack  2
      .locals init (int32 V_0,
               bool V_1)
      IL_0000:  nop
      IL_0001:  ldc.i4.0
      IL_0002:  stloc.0
      IL_0003:  br.s       IL_0022
      IL_0005:  nop
      IL_0006:  ldarg.0
      IL_0007:  ldloc.0
      IL_0008:  ldelem.u2
      IL_0009:  ldc.i4.s   50
      IL_000b:  ceq
      IL_000d:  ldc.i4.0
      IL_000e:  ceq
      IL_0010:  stloc.1
      IL_0011:  ldloc.1
      IL_0012:  brtrue.s   IL_001d
      IL_0014:  ldarg.0
      IL_0015:  ldloc.0
      IL_0016:  ldelem.u2
      IL_0017:  call       void [mscorlib]System.Console::Write(char)
      IL_001c:  nop
      IL_001d:  nop
      IL_001e:  ldloc.0
      IL_001f:  ldc.i4.1
      IL_0020:  add
      IL_0021:  stloc.0
      IL_0022:  ldloc.0
      IL_0023:  ldarg.0
      IL_0024:  ldlen
      IL_0025:  conv.i4
      IL_0026:  clt
      IL_0028:  stloc.1
      IL_0029:  ldloc.1
      IL_002a:  brtrue.s   IL_0005
      IL_002c:  ret
    } // end of method Program::ForLoop
    以下是:
    static void LinqSelect(char[] cs)
    用ldasm 查看其生成的MSIL代码:
    .method private hidebysig static void  LinqSelect(char[] cs) cil managed
    {
      // 代码大小       95 (0x5f)
      .maxstack  4
      .locals init (/* UNKNOWN TYPE (0x15)*/ V_0,
               class [mscorlib]System.Collections.Generic.'IEnumerable`1' V_1,
               void V_2,
               char V_3)
      IL_0000:  nop
      IL_0001:  ldarg.0
      IL_0002:  ldsfld     /* UNKNOWN TYPE (0x15)*/ LinqTest.Program::'CS$<>9__CachedAnonymousMethodDelegate1'
      IL_0007:  brtrue.s   IL_001c
      IL_0009:  ldnull
      IL_000a:  ldftn      bool LinqTest.Program::'<LinqSelect>b__0'(char)
      IL_0010:  newobj     instance void /* UNKNOWN TYPE (0x15)*/::.ctor(object,
                                                                         native int)
      IL_0015:  stsfld     /* UNKNOWN TYPE (0x15)*/ LinqTest.Program::'CS$<>9__CachedAnonymousMethodDelegate1'
      IL_001a:  br.s       IL_001c
      IL_001c:  ldsfld     /* UNKNOWN TYPE (0x15)*/ LinqTest.Program::'CS$<>9__CachedAnonymousMethodDelegate1'
      IL_0021:  call       <unknown token type 0x2b>
      IL_0026:  stloc.0
      IL_0027:  nop
      IL_0028:  ldloc.0
      IL_0029:  callvirt   instance /* UNKNOWN TYPE (0x15)*/ /* UNKNOWN TYPE (0x15)*/::GetEnumerator()
      IL_002e:  stloc.2
      .try
      {
        IL_002f:  br.s       IL_0041
        IL_0031:  ldloc.2
        IL_0032:  callvirt   instance !0 /* UNKNOWN TYPE (0x15)*/::get_Current()
        IL_0037:  stloc.1
        IL_0038:  nop
        IL_0039:  ldloc.1
        IL_003a:  call       void [mscorlib]System.Console::Write(char)
        IL_003f:  nop
        IL_0040:  nop
        IL_0041:  ldloc.2
        IL_0042:  callvirt   instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
        IL_0047:  stloc.3
        IL_0048:  ldloc.3
        IL_0049:  brtrue.s   IL_0031
        IL_004b:  leave.s    IL_005d
      }  // end .try
      finally
      {
        IL_004d:  ldloc.2
        IL_004e:  ldnull
        IL_004f:  ceq
        IL_0051:  stloc.3
        IL_0052:  ldloc.3
        IL_0053:  brtrue.s   IL_005c
        IL_0055:  ldloc.2
        IL_0056:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()
        IL_005b:  nop
        IL_005c:  endfinally
      }  // end handler
      IL_005d:  nop
      IL_005e:  ret
    } // end of method Program::LinqSelect
      

  7.   

    LINQ 效率肯定高写
    没环境没法测试
    使用testdriven.net
    或Stopwatch测试就知道了
      

  8.   

    的确是。。差了好多
    前面把Lost_Painting的程序改成了512个char的数组,搜索10000000次差了40+倍...用linq要1分多钟....
      

  9.   

    好像LINQ的发明者都承认 LINQ没想象中那么好,看VS2010中有没有质的提高了!
      

  10.   

    Linq的核心目标是让程序员关心What,而不是How,所以效率通常不及不用Linq的实现(除非实现的算法有问题),而且Linq的代码非常易理解(对程序员的友善),并且可以写的非常简洁
    把lz的Linq实现修改一下,就可以看到Linq在完成这个任务时完全只需要一句语句(尽管表达式有点长),并且在业务逻辑更复杂的现实情况下,Linq代码都优势就更明显了
    public static List<Account> GetAccountsC(List<User> users)
    {
       return (from item in users
               where item.Age > 21 && item.Age < 25
               select new Account
               {
                  ID = item.ID,
                  Name = item.FirstName + item.SecondName,
                  Age = item.Age
               }).ToList();
    }
      

  11.   


    也是。如 sp1234 所说的。但是我就想说“牺牲”了多少?Linq 和 Loop的选择应当是基于什么呢?
    效率和性能的选择?
    所以我就想知道,效率的差别,到底是不是“离谱”,还是可以承受。
      

  12.   

    简单的说
    偶尔访问的模块就用linq,频繁访问的就用loop效率差距上面不是试过了。。一个数量级的差距
      

  13.   

    因为测试方法的原因,这个测试结果未必可靠。执行40万次的话,肯定linq要慢很多,因为users里面的数据可能只有几条。
    如果users里面的数据量很大的话,两者的效率应该是差不多的,也许Linq还能快呢。
    LZ可以测试一下users里面有百万级的数据时的情况。
      

  14.   

    linq本身也是有很多写法。非linq也有许多方法,可以用不同的数据结构。只要实现方法得当,linq比普通方法慢的那部分完全可以忽略。大致慢10%左右。但linq带来的编写效率就不仅仅是10%了。而是100%~1000%的编写效率。lz可以这样权衡利弊。
      

  15.   

    Lost_Painting的测试是有问题的,不能参考,楼主你的那种情况,如果条件允许,还请用Linq,不过可以写得更加简洁些,也就是用lambda表达式。至于效率,不会慢多少的,编程方便带来的效益更加明显,设想我们经常需要把一些常用的方法保证成一个通用类来操作,以提高编程效率,而通用类往往比具体操作复杂,需要判断各种情况,有些是多余的,因此性能上是有损失的,但是却大大提高了编程速度,利大于弊。Linq也是这样的,微软帮我们包装好了很多静态扩展方法,如果没有那些方法,我们也有可能为了这些频繁的操作自己写一个类似Linq的通用类来呢。
      

  16.   


    对。我也觉得。如#19所说,如果是慢了 10%,那么我愿意选择 Linq,但如果是慢了50%,那么我就会抛弃它。
      

  17.   

    晕倒。我修改将您的代码,发现……你LinqSelect比LinqLoop多了两个“0”
      

  18.   

    实际相差,大概为:
    Loop|Linq
    1   |3
    需要多2倍的时间,感觉不值。
      

  19.   

    Linq并不是用来做循环的 Linq有它擅长的领域 比如做分组 肯定是比你的循环遍历要快 在什么场合 该用什么操作 大家都心里有数 拿LINQ来和foreach比循环速度 根本就没法比的 
      

  20.   

    请大家不要轻易下结论。使用如下代码测试,发现不同量级的数据,不同方法所需要的时间并不同。
    所以还是需要在不同环境下选择不同的方法。
    下面写出四种不同实现方法,所需时间各不相同。
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.IO;
    using System.Linq;namespace Test
    {
        static class Program
        {
            /// <summary>
            /// The main entry point for the application.
            /// </summary>
            [STAThread]
            static void Main()
            {
                Random rnd = new Random();
                int length = 0;
                while(true)
                {
                    string str = Console.ReadLine();
                    length = int.Parse(str);                List<User> uList = new List<User>(length);
                    for(int i = 0;i < length;i++)
                    {
                        uList.Add(new User(i, rnd.Next(15, 30), i.ToString(), "-" + (i + 1).ToString()));
                    }                Stopwatch sw = new Stopwatch();                sw.Reset();
                    sw.Start();
                    GetAccountsA(uList);
                    sw.Stop();
                    Console.WriteLine("GetAccountsA:{0,20:N0}", sw.ElapsedTicks);                sw.Reset();
                    sw.Start();
                    GetAccountsB(uList);
                    sw.Stop();
                    Console.WriteLine("GetAccountsB:{0,20:N0}", sw.ElapsedTicks);                sw.Reset();
                    sw.Start();
                    GetAccountsC(uList);
                    sw.Stop();
                    Console.WriteLine("GetAccountsC:{0,20:N0}", sw.ElapsedTicks);                sw.Reset();
                    sw.Start();
                    GetAccountsD(uList);
                    sw.Stop();
                    Console.WriteLine("GetAccountsD:{0,20:N0}", sw.ElapsedTicks);                Console.WriteLine("------------------");
                    Console.WriteLine();
                }
            }        public static List<Account> GetAccountsA(List<User> users)
            {
                List<Account> accounts = new List<Account>();
                foreach(User item in users)
                {
                    if(item.Age > 21 && item.Age < 25)
                    {
                        Account account = new Account();
                        account.ID = item.ID;
                        account.Name = item.FirstName + item.SecondName;
                        account.Age = item.Age;
                        accounts.Add(account);
                    }
                }
                return accounts;
            }
            public static List<Account> GetAccountsB(List<User> users)
            {
                var result = from item in users
                             where item.Age > 21 && item.Age < 25
                             select new Account
                             {
                                 ID = item.ID,
                                 Name = item.FirstName + item.SecondName,
                                 Age = item.Age
                             };
                return result.ToList<Account>();
            }
            public static List<Account> GetAccountsC(List<User> users)
            {
                var q = from item in users.Where(f => f.Age > 21 && f.Age < 25) select new Account
                {
                    ID = item.ID,
                    Name = item.FirstName + item.SecondName,
                    Age = item.Age
                };
                return q.ToList();
            }
            public static List<Account> GetAccountsD(List<User> users)
            {
                List<Account> accounts = new List<Account>(users.Count >> 1);
                foreach(User item in users)
                {
                    if(item.Age > 21 && item.Age < 25)
                    {
                        Account account = new Account();
                        account.ID = item.ID;
                        account.Name = item.FirstName + item.SecondName;
                        account.Age = item.Age;
                        accounts.Add(account);
                    }
                }
                return accounts;
            }
        }    class Account
        {
            public int ID { get; set; }
            public string Name { get; set; }
            public int Age { get; set; }
        }
        class User
        {
            public User(int ID, int Age, string FirstName, string SecondName)
            {
                this.ID = ID;
                this.Age = Age;
                this.FirstName = FirstName;
                this.SecondName = SecondName;
            }        public int ID { get; set; }
            public int Age { get; set; }
            public string FirstName { get; set; }
            public string SecondName { get; set; }
        }
    }
      

  21.   



    呵呵,确实,我手误,我修正一下测试结果,Linq测试次数比For循环测试次数多了一个0
    给大家带来不便敬请谅解
    从这个问题看出了,一定要用一个统一的变量/常数,不要到处用1000这类,哈哈
    编码规范啊,编码规范,好处从这里就看出来了..

    还是楼主细心.感谢指正错误.我重新更新代码与测试结果:
    测试结果: 循环1千万次For循环:  283.0162 ms 
    Linq:    981.0561ms 因此是 1:3 左右的性能比代码如下:(用常数放循环次数了,避免手误,呵呵,不好意思呐)
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;namespace LinqTest
    {
        class Program
        {
             const int LoopCount = 10000000;
            static void Main(string[] args)
            {
                char[] cs = new char[3] { '1', '2', '3' };
                DateTime BeginTime = DateTime.Now;
                DateTime EndTime;
                for (int i = 0; i < LoopCount; i++)
                {
                    ForLoop(cs);
                }
                EndTime = DateTime.Now;
                Console.WriteLine(EndTime.Subtract(BeginTime).TotalMilliseconds.ToString() + " ms");            BeginTime = DateTime.Now;
                for (int i = 0; i < LoopCount; i++)
                {
                    LinqSelect(cs);
                }
                EndTime = DateTime.Now;
                Console.WriteLine(EndTime.Subtract(BeginTime).TotalMilliseconds.ToString() + " ms");            Console.ReadKey();
            }        static void ForLoop(char[] cs)
            {
                for (int i = 0; i < cs.Length; i++)
                {
                    if (cs[i] == '2') ; //Console.Write(cs[i]);
                }
            }        static void LinqSelect(char[] cs)
            {
                var o = from c in cs
                        where c == '2'
                        select c;
                foreach (var r in o)
                {
                    // Console.Write(r);
                }
            }
        }
    }
      

  22.   

    呵呵,确实,我手误,我修正一下测试结果,Linq测试次数比For循环测试次数多了一个0给大家带来不便敬请谅解 从这个问题看出了,一定要用一个统一的变量/常数,不要到处用1000这类,哈哈编码规范啊,编码规范,好处从这里就看出来了.. 还是楼主细心.感谢指正错误. 
      

  23.   

    您的精心回复,也让人敬佩。
    虽然最终“Linq”在【效率】上失败。也对,不同场合。可能我比较“贪”效率。最终我决定尽量不去使用 Linq。但 #27 所说的,也是有道理之极!
      

  24.   

    LZ可以测试一下这种情况,再来看看Linq的效率,就会有不同的看法,并知道究竟是慢在哪里了!
    现在判断linq效率低,还有些为时过早。(测试需自行注释掉For或Linq的代码)using System;
    using System.Collections.Generic;
    using System.Linq;namespace Robot
    {
        class Program
        {
            static void Main(string[] args)
            {
                Random rnd = new Random();
                int[] items = new int[10000000];
                List<int> forItems = new List<int>();            for (int i = 0; i < items.Length; i++)
                    items[i] = rnd.Next(1000);            DateTime BeginTime = DateTime.Now;            var linqItems = from item in items where item > 300 && item < 800 select item;            for (int i = 0; i < items.Length; i++)
                    if (items[i] > 300 && items[i] < 800)
                        forItems.Add(items[i]);            DateTime EndTime = DateTime.Now;            Console.WriteLine(EndTime.Subtract(BeginTime).TotalMilliseconds.ToString() + " ms");
                Console.ReadKey();
            }
        }
    }
      

  25.   

    楼上的测试过程不平等.
    Linq只是把结果集取出,并未在新增到List中.
    For循环在历遍的同时把结果放置到了List中.因此Linq测试部分还需要增加新增到List的动作,这样测试才较为公平.测试代码:
    一个一亿的Int数组.
    For循环:  1996.1141 ms
    Linq:    1806.1033 ms差异并不大了.声明一下,我可从来没有跟楼主说过不要用Linq,我只是针对楼主说的Linq与For循环进行性能对比测试.
    看我之前的代码,我也是一直在用Linq,只要实现了IEnumerable(T)接口的类,我就会优先用Linq.
    快速开发,何乐而不为呢?你爽,老板也爽.参考之前几楼的各位所说,楼主不要因为这点点的效能就不使用Linq.牺牲一点效能换来高效的开发效率,绝对值得.

    using System;
    using System.Collections.Generic;
    using System.Linq;namespace Robot
    {
        class Program
        {
            static void Main(string[] args)
            {
                Random rnd = new Random();
                int[] items = new int[100000000]; //一个含有一亿个Int数组,数据量够大了
                List<int> forItems = new List<int>();            for (int i = 0; i < items.Length; i++)
                    items[i] = rnd.Next(1000);            forItems.Clear();
                DateTime BeginTime = DateTime.Now;
                DateTime EndTime = DateTime.Now;
                var linqItems = from item in items
                                where item > 300 && item < 800
                                select item;          //加这一段测试才是最完整的.因为,上面的Linq只是查询出结果,结果还在内存中.需要再取出来放置到List中.            //两种用法,随便使用哪种.
                //方法一
                foreach (var i in linqItems)
                {
                    forItems.Add(i);
                }
                //方法二,测试暂时用方法一
               // forItems.AddRange(linqItems);            EndTime = DateTime.Now;
                Console.WriteLine(EndTime.Subtract(BeginTime).TotalMilliseconds.ToString() + " ms");            forItems.Clear();
                BeginTime = DateTime.Now;
                for (int i = 0; i < items.Length; i++)
                {
                    if (items[i] > 300 && items[i] < 800) forItems.Add(items[i]);
                }
                EndTime = DateTime.Now;
                Console.WriteLine(EndTime.Subtract(BeginTime).TotalMilliseconds.ToString() + " ms");
                Console.ReadKey();
            }
        }
    }
      

  26.   

    我晕,CSDN搞什么.换行全不见了?楼上的测试过程不平等. 
    Linq只是把结果集取出,并未在新增到List中. 
    For循环在历遍的同时把结果放置到了List中.
    因此Linq测试部分还需要增加新增到List的动作,这样测试才较为公平. 测试代码: 一个一亿的Int数组. For循环: 1996.1141 ms 
    Linq: 1806.1033 ms 差异并不大了. 声明一下,我可从来没有跟楼主说过不要用Linq,我只是针对楼主说的Linq与For循环进行性能对比测试.
     看我之前的代码,我也是一直在用Linq,只要实现了IEnumerable(T)接口的类,我就会优先用Linq. 
    快速开发,何乐而不为呢?你爽,老板也爽. 参考之前几楼的各位所说,楼主不要因为这点点的效能就不使用Linq.牺牲一点效能换来高效的开发效率,绝对值得.
      

  27.   

    呵呵,其实我用的也是以偏概全的方法,让Linq的效率显得特别高。双方的效率本来就是一个量级的,
    谁也不会比谁差太多。以我使用linq的情况来看,让一个Linq语句执行上百万次,效率肯定会低,
    但用一句Linq来处理大量的数据,效率是可以的。
      

  28.   

    修正,呵呵
    打反了.
    看来近几天快过年了,手误不是一般的多.For循环: 1806.1033 ms 
    Linq:    1996.1141 ms 
      

  29.   

    刚刚装上vs2010,发现用linq有个大的优势:易于并行计算!
    这是两个求素数的方法,使用并行计算效率提高近一半。都得益于AsParallel()。
    只要加上AsParallel(),一切都变成并行。        private void AppendPrimeA(int e)
            {
                for(int i = _prime.Max();i < e;i++)
                {
                    if(!_prime.AsParallel().Any(f => i % f == 0))
                        _prime.Add(i);
                }
            }        private void AppendPrimeB(int count)
            {
                int i = _prime.Max();
                while(count > 0)
                {
                    i++;
                    if(!_prime.AsParallel().Any(f => i % f == 0))
                    {
                        _prime.Add(i);
                        count--;
                    }
                }
            }
      

  30.   

    还是得看场合和需求的。如果说是对效率十分追求的场合的话当然就不合适了(比如说数据提取很频繁)。
    如果数据量小。对效率要求比较松的话,当然用LINQ好啦。
    这个还是看你怎么用啦~!~
      

  31.   

    看情况使用而已,本人试过用linq代替for循环快了10倍效率,有时用却差不多,很想知道是否有规律可寻,知道的朋友请相告,谢谢!