注意:我知道这段代码与roslyn不兼容
为什么 CreateDelegate 比直接调用更快?
任何人都可以解释为什么 Delegate.CreateDelegate 比直接调用委托更快吗?
(.NET 3.5,调试/发布版本类似..)
参见示例代码:
static void Main(string[] args)
{
var myDelegate = new Func<string, string>((s) => s);
// Direct Call
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 10000000; i++)
{
myDelegate("test");
}
sw.Stop();
Console.WriteLine("DirectCall: \t\t{0}ms" ,sw.ElapsedMilliseconds);
sw.Reset();
// CreateDeleagetCall
var myDelegateCaller = (Func<string, string>)Delegate.CreateDelegate(typeof(Func<string, string>), myDelegate.Method);
sw.Start();
for (int i = 0; i < 10000000; i++)
{
myDelegateCaller("test");
}
sw.Stop();
Console.WriteLine("CreateDelegateCall: \t{0}ms", sw.ElapsedMilliseconds);
Console.ReadLine();
}
.Net core 8.0 和 BenchmarkDotNet - 相同的结果:
using System.Linq.Expressions;
using System.Reflection;
using BenchmarkDotNet.Attributes;
namespace SomeBenchmarks;
public class InstanceMethodInvoke
{
readonly Foo _foo = new();
Action<Foo> _exprAction;
Action _delegateAction;
[GlobalSetup]
public void Setup()
{
var methodInfo = typeof(Foo).GetMethod("Bar", BindingFlags.Public | BindingFlags.Instance)
?? throw new MissingMemberException(nameof(Foo), nameof(Foo.Bar));
var instanceExpr = Expression.Parameter(typeof(Foo));
_exprAction = Expression.Lambda<Action<Foo>>(Expression.Call(instanceExpr, methodInfo), instanceExpr).Compile();
_delegateAction = (Action)Delegate.CreateDelegate(typeof(Action), _foo, methodInfo);
}
[Benchmark]
public void InvokeFuncByExpression()
{
foreach (var _ in Enumerable.Repeat(1, 1000))
_exprAction(_foo);
}
[Benchmark]
public void InvokeFuncByDelegate()
{
foreach (var _ in Enumerable.Repeat(1, 1000))
_delegateAction();
}
[Benchmark(Baseline = true)]
public void DirectCall()
{
foreach (var _ in Enumerable.Repeat(1, 1000))
_foo.Bar();
}
}
public class Foo
{
public void Bar(){}
}
基准测试结果:
// * Summary *
BenchmarkDotNet v0.13.12, Windows 10 (10.0.19045.4291/22H2/2022Update)
Intel Core i7-10700F CPU 2.90GHz, 1 CPU, 16 logical and 8 physical cores
.NET SDK 9.0.100-preview.1.24101.2
[Host] : .NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX2
DefaultJob : .NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX2
| Method | Mean | Error | StdDev | Ratio |
|----------------------- |---------:|----------:|----------:|------:|
| InvokeFuncByExpression | 1.312 μs | 0.0061 μs | 0.0057 μs | 1.12 |
| InvokeFuncByDelegate | 1.104 μs | 0.0040 μs | 0.0037 μs | 0.94 |
| DirectCall | 1.172 μs | 0.0051 μs | 0.0045 μs | 1.00 |