Oma*_*mar 11 c# lambda delegates anonymous-function
我假设lambda functions,delegates并且anonymous functions使用相同的主体将具有相同的"速度",但是,运行以下简单程序:
static void Main(string[] args)
{
List<int> items = new List<int>();
Random random = new Random();
for (int i = 0; i < 10000000; i++)
{
items.Add(random.Next());
}
Stopwatch watch;
IEnumerable<int> result;
Func<int, bool> @delegate = delegate(int i)
{
return i < 500;
};
watch = Stopwatch.StartNew();
result = items.Where(@delegate);
watch.Stop();
Console.WriteLine("Delegate: {0}", watch.Elapsed.TotalMilliseconds);
Func<int, bool> lambda = i => i < 500;
watch = Stopwatch.StartNew();
result = items.Where(lambda);
watch.Stop();
Console.WriteLine("Lambda: {0}", watch.Elapsed.TotalMilliseconds);
watch = Stopwatch.StartNew();
result = items.Where(i => i < 500);
watch.Stop();
Console.WriteLine("Inline: {0}", watch.Elapsed.TotalMilliseconds);
Console.ReadLine();
}
Run Code Online (Sandbox Code Playgroud)
我明白了:
代表:4.2948毫秒
Lambda:0.0019毫秒
匿名:0.0034毫秒
虽然可以忽略不计,为什么这三种 - 显然是相同的 - 方法以不同的速度运行?引擎盖下发生了什么?
更新:
正如评论所建议的那样,以下"强制" Where通过呼吁ToList()它.此外,还添加了一个循环以提供更多运行数据:
while (true)
{
List<int> items = new List<int>();
Random random = new Random();
for (int i = 0; i < 10000000; i++)
{
items.Add(random.Next());
}
Stopwatch watch;
IEnumerable<int> result;
Func<int, bool> @delegate = delegate(int i)
{
return i < 500;
};
watch = Stopwatch.StartNew();
result = items.Where(@delegate).ToList();
watch.Stop();
Console.WriteLine("Delegate: {0}", watch.Elapsed.TotalMilliseconds);
Func<int, bool> lambda = i => i < 500;
watch = Stopwatch.StartNew();
result = items.Where(lambda).ToList();
watch.Stop();
Console.WriteLine("Lambda: {0}", watch.Elapsed.TotalMilliseconds);
watch = Stopwatch.StartNew();
result = items.Where(i => i < 500).ToList();
watch.Stop();
Console.WriteLine("Inline: {0}", watch.Elapsed.TotalMilliseconds);
Console.WriteLine(new string('-', 12));
}
Run Code Online (Sandbox Code Playgroud)
上述代码每个函数的结果约为120毫秒.
Col*_*inE 18
其他人的结果表明性能是相同的:
正如评论中所指出的,微观基准往往具有误导性.有太多因素无法控制,JIT优化,垃圾收集周期等......
看到这个相关的问题:
最后,我认为你的测试存在根本缺陷!您使用Linq Where扩展方法来执行代码.但是,Linq使用延迟评估,只有在开始迭代结果时才会执行代码!
Jon*_*eet 14
lambda表达式是一个匿名函数."匿名函数"指的是lambda表达式或匿名方法(这就是你所谓的代码中的"代表").
这三个操作都使用了代理.第二个和第三个都使用lambda表达式.所有三个都将以相同的方式执行,具有相同的性能特征.
请注意,有可能是在两者之间性能差异:
Func<int, int> func = x => ...;
for (int i = 0; i < 10000; i++) {
CallFunc(func);
}
Run Code Online (Sandbox Code Playgroud)
和
for (int i = 0; i < 10000; i++) {
CallFunc(x => ...) // Same lambda as before
}
Run Code Online (Sandbox Code Playgroud)
这取决于编译器是否能够缓存由lambda表达式创建的委托.这将取决于它是否捕获变量等.
例如,考虑以下代码:
using System;
using System.Diagnostics;
class Test
{
const int Iterations = 1000000000;
static void Main()
{
AllocateOnce();
AllocateInLoop();
}
static void AllocateOnce()
{
int x = 10;
Stopwatch sw = Stopwatch.StartNew();
int sum = 0;
Func<int, int> allocateOnce = y => y + x;
for (int i = 0; i < Iterations; i++)
{
sum += Apply(i, allocateOnce);
}
sw.Stop();
Console.WriteLine("Allocated once: {0}ms", sw.ElapsedMilliseconds);
}
static void AllocateInLoop()
{
int x = 10;
Stopwatch sw = Stopwatch.StartNew();
int sum = 0;
for (int i = 0; i < Iterations; i++)
{
sum += Apply(i, y => y + x);
}
sw.Stop();
Console.WriteLine("Allocated in loop: {0}ms", sw.ElapsedMilliseconds);
}
static int Apply(int loopCounter, Func<int, int> func)
{
return func(loopCounter);
}
}
Run Code Online (Sandbox Code Playgroud)
编译器很聪明,但仍然存在差异.使用Reflector,我们可以看到它AllocateInLoop被有效地编译为:
private static void AllocateInLoop()
{
Func<int, int> func = null;
int x = 10;
Stopwatch stopwatch = Stopwatch.StartNew();
int sum = 0;
for (int i = 0; i < Iterations; i++)
{
if (func == null)
{
func = y => y + x;
}
sum += Apply(i, func);
}
stopwatch.Stop();
Console.WriteLine("Allocated in loop: {0}ms", stopwatch.ElapsedMilliseconds);
}
Run Code Online (Sandbox Code Playgroud)
所以仍然只创建了一个委托实例,但循环中还有额外的逻辑 - 基本上是对每次迭代进行额外的无效测试.
在我的机器上,性能差异大约为15%.
| 归档时间: |
|
| 查看次数: |
9878 次 |
| 最近记录: |