Здравствуйте, Пельмешко, Вы писали:
П>Здравствуйте, 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));
}