Информация об изменениях

Сообщение Re[93]: Тормознутость и кривость linq от 28.04.2016 12:06

Изменено 28.04.2016 12:36 Serginio1

Здравствуйте, alex_public, Вы писали:

_>Здравствуйте, ·, Вы писали:


_>·>В смысле в аналог linq? И в чём прикол точить эту шашку два года, когда есть готовая.


_>Ну вот на SO в начале использовали Linq, а потом выкинули его в помойку в пользу использования голых строк. Наверное там ничего не имеющие непрофессионалы сидят, да? ))) В отличие от многочисленных экспертов-теоретиков с нашего форума. )))


N>>>Питон — это потому, что мне легче на нём быстро формулировать. Мог быть любой другой язык.

_>·>Так собственно linq это и делает у себя внутрях по сути во время runtime, а alex_public говорил что это тормоза — используйте compile time.

_>Ничего подобного. Linq делает не это. Точнее не только это. В начале он анализирует (через тормозную рефлексию) выражение и генерирует из него код склейки и только потом запускает собственно этот код. Причём как раз этот анализ занимает во много раз больше времени, чем собственно склейка строк. И именно оттуда и идут тормоза.

О поподробнее пожалуйста. Там на самом деле деревья выражений Исследование скорости вызова метода различными способами
Кроме того запросы кэшируются если это возможно после первого вызова так как заранее не известен провайдер, так что основные затраты только на первый вызов.
Там где динамические запросы обычно время вызова значительно выше времени компиляции запроса. Не забывай, что на стороне сервера такие запросы могут быть не закэшированы из-за множества вариаций
Re[93]: Тормознутость и кривость linq
Здравствуйте, alex_public, Вы писали:

_>Здравствуйте, ·, Вы писали:


_>·>В смысле в аналог linq? И в чём прикол точить эту шашку два года, когда есть готовая.


_>Ну вот на SO в начале использовали Linq, а потом выкинули его в помойку в пользу использования голых строк. Наверное там ничего не имеющие непрофессионалы сидят, да? ))) В отличие от многочисленных экспертов-теоретиков с нашего форума. )))


N>>>Питон — это потому, что мне легче на нём быстро формулировать. Мог быть любой другой язык.

_>·>Так собственно linq это и делает у себя внутрях по сути во время runtime, а alex_public говорил что это тормоза — используйте compile time.

_>Ничего подобного. Linq делает не это. Точнее не только это. В начале он анализирует (через тормозную рефлексию) выражение и генерирует из него код склейки и только потом запускает собственно этот код. Причём как раз этот анализ занимает во много раз больше времени, чем собственно склейка строк. И именно оттуда и идут тормоза.

О поподробнее пожалуйста. Там на самом деле деревья выражений Исследование скорости вызова метода различными способами
Кроме того запросы кэшируются если это возможно после первого вызова так как заранее не известен провайдер, так что основные затраты только на первый вызов.

https://habrahabr.ru/post/83169/

Вот код нашего нового создателя:


class ExpressionCreator<T> : ICreator<T>
 {
   private readonly Func<Dictionary<string, object>, T> _creator;

   public ExpressionCreator()
   {
     var type = typeof(T);
     var newExpression = Expression.New(type);
     var dictParam = Expression.Parameter(typeof(Dictionary<string, object>), "d");
     var list = new List<MemberBinding>();
     var propertyInfos = type.GetProperties(BindingFlags.Instance |
                         BindingFlags.Public |
                         BindingFlags.SetProperty);
     foreach (var propertyInfo in propertyInfos)
     {
       Expression call = Expression.Call(
                          typeof (DictionaryExtension),
                          "GetValue", new[] {propertyInfo.PropertyType},
                          new Expression[]
                            {
                              dictParam,
                              Expression.Constant(propertyInfo.Name)
                            });

       MemberBinding mb = Expression.Bind(propertyInfo.GetSetMethod(), call);
       list.Add(mb);
     }

     var ex = Expression.Lambda<Func<Dictionary<string, object>, T>>(
                                       Expression.MemberInit(newExpression, list),
                                       new[] {dictParam});
     _creator = ex.Compile();
   }
   public T Create(Dictionary<string, object> props)
   {
     return _creator(props);
   }
 }

* This source code was highlighted with Source Code Highlighter.

Мы, фактически, повторяем код, созданный компилятором, но динамически обрабатываем все свойства любого данного объекта. (Построение полностью аналогично разобранному выше).


Новый создатель создается 0,01 секунду (что в 10 раз медленнее, чем у reflection, но конструктор вызывается только один раз) и тратит 0,017 секунд на создание 10000 объектов (что в 70 раз быстрее).


Кстати, если создавать объект Foo напрямую

internal class DirectCreator : ICreator<Foo>
 {
   public Foo Create(Dictionary<string, object> props)
   {
     return new Foo
     {
       Name = props.GetValue<string>("Name"),
       Value = props.GetValue<int>("Value")
     };
   }
 }


то это получается всего в два раза быстрее, чем через expressions.


Вот такие штуки позволяют нам делать Expression trees.


Там где динамические запросы обычно время вызова значительно выше времени компиляции запроса. Не забывай, что на стороне сервера такие запросы могут быть не закэшированы из-за множества вариаций