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>();
}菜菜的我,用笨拙的方式进行测试,感觉上在效率没有什么差别。可能代码写的“不利于测试”,也可能测试的方式错误。能力有限,故而问之。如果您知道,不妨分享您的心得与见解吧?
{
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>();
}菜菜的我,用笨拙的方式进行测试,感觉上在效率没有什么差别。可能代码写的“不利于测试”,也可能测试的方式错误。能力有限,故而问之。如果您知道,不妨分享您的心得与见解吧?
我测试的Linq,是用于进行数据的筛选。不知道用Linq的效率会低的“离谱”,还是相差无几?
循环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);
}
}
}
}
我觉得foreach和Linq都是用GetGenerator的吧,所以效率上差不多。
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
没环境没法测试
使用testdriven.net
或Stopwatch测试就知道了
前面把Lost_Painting的程序改成了512个char的数组,搜索10000000次差了40+倍...用linq要1分多钟....
把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();
}
也是。如 sp1234 所说的。但是我就想说“牺牲”了多少?Linq 和 Loop的选择应当是基于什么呢?
效率和性能的选择?
所以我就想知道,效率的差别,到底是不是“离谱”,还是可以承受。
偶尔访问的模块就用linq,频繁访问的就用loop效率差距上面不是试过了。。一个数量级的差距
如果users里面的数据量很大的话,两者的效率应该是差不多的,也许Linq还能快呢。
LZ可以测试一下users里面有百万级的数据时的情况。
对。我也觉得。如#19所说,如果是慢了 10%,那么我愿意选择 Linq,但如果是慢了50%,那么我就会抛弃它。
Loop|Linq
1 |3
需要多2倍的时间,感觉不值。
所以还是需要在不同环境下选择不同的方法。
下面写出四种不同实现方法,所需时间各不相同。
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; }
}
}
呵呵,确实,我手误,我修正一下测试结果,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);
}
}
}
}
虽然最终“Linq”在【效率】上失败。也对,不同场合。可能我比较“贪”效率。最终我决定尽量不去使用 Linq。但 #27 所说的,也是有道理之极!
现在判断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();
}
}
}
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();
}
}
}
Linq只是把结果集取出,并未在新增到List中.
For循环在历遍的同时把结果放置到了List中.
因此Linq测试部分还需要增加新增到List的动作,这样测试才较为公平. 测试代码: 一个一亿的Int数组. For循环: 1996.1141 ms
Linq: 1806.1033 ms 差异并不大了. 声明一下,我可从来没有跟楼主说过不要用Linq,我只是针对楼主说的Linq与For循环进行性能对比测试.
看我之前的代码,我也是一直在用Linq,只要实现了IEnumerable(T)接口的类,我就会优先用Linq.
快速开发,何乐而不为呢?你爽,老板也爽. 参考之前几楼的各位所说,楼主不要因为这点点的效能就不使用Linq.牺牲一点效能换来高效的开发效率,绝对值得.
谁也不会比谁差太多。以我使用linq的情况来看,让一个Linq语句执行上百万次,效率肯定会低,
但用一句Linq来处理大量的数据,效率是可以的。
打反了.
看来近几天快过年了,手误不是一般的多.For循环: 1806.1033 ms
Linq: 1996.1141 ms
这是两个求素数的方法,使用并行计算效率提高近一半。都得益于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--;
}
}
}
如果数据量小。对效率要求比较松的话,当然用LINQ好啦。
这个还是看你怎么用啦~!~