这个问题的答案是什么了IEnumerable预期的性能? 说也没有办法了解迭代任意IEnumerable的性能点儿。 每次迭代可以打一个数据库或进行网络电话serivce; 或者它可能只是一个数组/列表中返回的下一个项目。
鉴于此,有表示“这是快”的好办法? 例如,用T[]
或List<T>
代替IEnumerable<T>
我知道从去T[i]
至T[i+1]
会很快。 (当然,迫使枚举返回一个列表/阵列可以创建其他性能问题。 List<T>
也暴露可编辑的语义。)
反之,将返回IQueryable<T>
代替IEnumerable<T>
是表示“这是慢”的好办法? 或者,也许IEnumerable<Task<T>>
?
的客户C
没有knowning所述的方式IEnumerable<T>
旨意具有显着不同的性能特性。
class C
{
readonly T[] m_data;
public IEnumerable<T> ThisWillIterateQuickly { get { return m_data; } }
public IEnumeralbe<T> ThisWillIterateSlowly
{
get
{
T retval = ... an expensive database call ...;
yield return retval;
}
}
public IQueryable<T> IsThisBetterForSlow { get { return ThisWillIterateSlowly; } }
public T[] IsThisAGoodWayForFast { get { return m_data; } }
}
相反,会返回IQueryable的,而不是IEnumerable的是,表示“这是慢”的好办法?
不, IQueryable<T>
从固有IEnumerable<T>
......与问题IEnumerable<T>T
的是,它可能是IQueryable<T>
与迭代时,像查询远程数据库或类似的东西AA巨大的侧影响。
有趣的是不是?
你可能要问IEnumerable<T>
VS List<T>
这第二个,绝对有它的数据,并不需要从别的地方得到它。
如果你想保证迭代将不包含任何意外,那么我同意,露出T[]
-它枚举不能被重写,因为你不能从数组继承。 迭代也可以自由的副作用,同样不能说对IEnumerable<T>
不过,我不同意,露出一个数组表示这个消息,这是更重要的(在我看来)。 事物的性能从来没有真正在代码中表示,除非你开始命名的东西CheapIteration
或ExpensiveIteration
。
在硬币的另一面,有一个数组,你只需移动点播迭代的性能问题,以填充阵列的点。 这是保证充分击中性能问题,因为这将是任何供应数组内容进行完整的迭代。 在一个IEnumerable<T>
如果迭代停止时,也是如此性能问题-最快代码是不运行的代码。
思考这个多一些之后,看来问题/问题实际上集中在行为/性能IEnumerator.MoveNext()
使用Visual Studio 2012,我能创造的异步版本IEnumerator
和IEnumerable
:
public interface IAsyncEnumerator<T> : IDisposable
{
Task<T> CurrentAsync { get; }
Task<bool> MoveNextAsync();
Task ResetAsync();
}
public interface IAsyncEnumerable<T>
{
IAsyncEnumerator<T> GetAsyncEnumerator();
}
这种方法的缺点是没有很多的语言支持; 上述不会工作foreach
。 但是,扩展方法可以缓解疼痛:
public static class EnumeratorExtensions
{
public static void ForEach<T>(this IEnumerable<T> enumerable, Action<T> action)
{
using (var enumerator = enumerable.GetEnumerator())
{
while (enumerator.MoveNext())
action(enumerator.Current);
}
}
public static async Task ForEachAsync<T>(this IAsyncEnumerable<T> enumerable, Action<T> action)
{
using (var enumerator = enumerable.GetAsyncEnumerator())
{
while (await enumerator.MoveNextAsync())
action(await enumerator.CurrentAsync);
}
}
}
我通常使用属性返回“快”枚举和方法“缓慢”。
你的问题是使用异步方法和设计尽可能的说法。 然后,它其实并不重要枚举需要多长时间,作为UI响应和用户快乐;-)