I need to invoke a generic method by MethodInfo.Invoke
, because I only have generic type at runtime. I heard about MethodInfo.Invoke performance issue, that it's a lot slower than call method directly. So, to test about performance, I created benchmark program:
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
namespace Benmarking
{
class Program
{
static void Main(string[] args)
{
var summary = BenchmarkRunner.Run<BenchmarkTest>();
}
}
public class BenchmarkTest
{
private const int _count = 1000000;
private static readonly ConcurrentDictionary<Type, Type> _typesResult = new ConcurrentDictionary<Type, Type>();
private static readonly ConcurrentDictionary<Type, MethodInfo> _methodsInfo = new ConcurrentDictionary<Type, MethodInfo>();
[Benchmark]
public async Task<object> InvokeCastGenericCall()
{
return await ((dynamic)new Test()).GetList(new Respone<object>(), _count).ConfigureAwait(false);
}
[Benchmark]
public async Task<object> DirectCall()
{
return await new Test().GetList(new Respone<object>(), _count).ConfigureAwait(false);
}
[Benchmark]
public async Task<object> InvokeMethodCall()
{
var typeResult = typeof(object);
var methodInfo = typeof(Test).GetMethod(nameof(Test.GetList)).MakeGenericMethod(typeResult);
Task task = (Task)methodInfo.Invoke(new Test(), new object[] { new Respone<object>(), _count });
await task.ConfigureAwait(false);
return ((dynamic)task).Result;
}
[Benchmark]
public async Task<object> InvokeMethodCall_Cache()
{
var typeResult = _typesResult.GetOrAdd(typeof(object), type => typeof(object));
var methodInfo = _methodsInfo.GetOrAdd(typeResult, type => typeof(Test).GetMethod(nameof(Test.GetList)).MakeGenericMethod(type));
Task task = (Task)methodInfo.Invoke(new Test(), new object[] { new Respone<object>(), _count });
await task.ConfigureAwait(false);
return ((dynamic)task).Result;
}
}
public class Test
{
public async Task<List<T>> GetList<T>(Respone<T> input, int count) where T : class, new()
{
IEnumerable<T> Get()
{
for (var i = 0; i < count; i++)
yield return new T();
}
return await Task.FromResult(Get().ToList());
}
}
public class Respone<T> where T : new()
{
}
}
The results were strange, MethodInfo.Invoke even faster than call method directly. And the fastest is cast object to dynamic and call dynamic method. The result is present in below image:
I was worried about where I made the wrong benchmark? Can anyone explain it to me? Thank you very much!
Aucun commentaire:
Enregistrer un commentaire