Re[6]: Как ускорить yield return?
От: Sinix  
Дата: 23.02.10 04:56
Оценка:
Здравствуйте, Пельмешко, Вы писали:

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


S>> Правда я вообще не представляю, как yield many может повлиять на производительность.


П>Вот так:


Дык это ж бубль гум хвостовая рекурсия. И обходится оно, как всегда, заведением собственного стека.

П>То есть если у Вас сейчас итератор вызвал сам себя (или другой итератор) 1000 раз, то чтобы получить очередное значение, надо добраться до энумератора, который вложен в 1000 экземпяров итераторов — MoveNext() и get_Current() будет вызваны 1000 раз... А у yield return-итератора нужный энумератор всегда лежит на вершине стека, один MoveNext() считай...

Ну, можно ещё и не так извратиться. Можно по 2 раза всех переспрашивать. И рандомно встряхивать стек. чтоб совсем уж быстро было.

П>Попробуйте на нынешних итераторах что-нибудь сильно рекурсивное написать, тогда может даже невооружённым глазом заметна будет разница


Не очень заметна. Специально не мерял, но узким местом не становилось.

  private static IEnumerable<T> UngroupRecurseEnumerator<T>(
      IEnumerable<T> source, Func<T, IEnumerable<T>> getItemsFunction)
    {
      Stack<IEnumerator<T>> stack = new Stack<IEnumerator<T>>();
      stack.Push(source.GetEnumerator());
      do
      {
        IEnumerator<T> enumerator = stack.Peek();
        if (enumerator.MoveNext())
        {
          T current = enumerator.Current;
          stack.Push(getItemsFunction(current).GetEnumerator());
          yield return current;
        }
        else
        {
          stack.Pop();
        }
      }
      while (HasValues(stack));
    }
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.