Учитывая этот класс:
/// <summary>
/// Dummy implementation of a parser for the purpose of the test
/// </summary>
class Parser
{
public List<T> ReadList<T>(Func<T> readFunctor)
{
return Enumerable.Range(0, 10).Select(i => readFunctor()).ToList();
}
public int ReadInt32()
{
return 12;
}
public string ReadString()
{
return "string";
}
}
Я пытаюсь сгенерировать следующий вызов со скомпилированным деревом лямбда-выражений:
Parser parser = new Parser();
List<int> list = parser.ReadList(parser.ReadInt32);
Однако производительность не совсем такая ...
class Program
{
private const int MAX = 1000000;
static void Main(string[] args)
{
DirectCall();
LambdaCall();
CompiledLambdaCall();
}
static void DirectCall()
{
Parser parser = new Parser();
var sw = new Stopwatch();
sw.Start();
for (int i = 0; i < MAX; i++)
{
List<int> list = parser.ReadList(parser.ReadInt32);
}
sw.Stop();
Console.WriteLine("Direct call: {0} ms", sw.ElapsedMilliseconds);
}
static void LambdaCall()
{
Parser parser = new Parser();
var sw = new Stopwatch();
sw.Start();
for (int i = 0; i < MAX; i++)
{
List<int> list = parser.ReadList(() => parser.ReadInt32());
}
sw.Stop();
Console.WriteLine("Lambda call: {0} ms", sw.ElapsedMilliseconds);
}
static void CompiledLambdaCall()
{
var parserParameter = Expression.Parameter(typeof(Parser), "parser");
var lambda = Expression.Lambda<Func<Parser, List<int>>>(
Expression.Call(
parserParameter,
typeof(Parser).GetMethod("ReadList").MakeGenericMethod(typeof(int)),
Expression.Lambda(
typeof(Func<int>),
Expression.Call(
parserParameter,
typeof(Parser).GetMethod("ReadInt32")))),
parserParameter);
Func<Parser, List<int>> func = lambda.Compile();
Parser parser = new Parser();
var sw = new Stopwatch();
sw.Start();
for (int i = 0; i < MAX; i++)
{
List<int> list = func(parser);
}
sw.Stop();
Console.WriteLine("Compiled lambda call: {0} ms", sw.ElapsedMilliseconds);
}
}
Вот результаты в миллисекундах на моем компьютере:
Direct call: 647 ms
Lambda call: 641 ms
Compiled lambda call: 5861 ms
Я не понимаю, почему скомпилированный лямбда-вызов так медленно.
И я забыл сказать, что мой тест выполняется в режиме выпуска с включенной опцией «Оптимизировать код».
Обновление : сравнительный анализ изменен на основе DateTime.Now
на Секундомер
.
Кто-нибудь знает, как настроить лямбда-выражение для повышения производительности скомпилированного лямбда-вызова?