我最近一直在玩 IAsyncEnumerables,有一点我无法理解它在幕后是如何工作的。
考虑以下代码:
private async Task Test()
{
var t = new List<int>();
await foreach (var number in Numbers().Take(5).ConfigureAwait(false))
{
t.Add(number);
}
}
int[] myIntArray = new int[10] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
private async IAsyncEnumerable<int> Numbers()
{
foreach (var element in myIntArray)
{
yield return element;
}
}
所以困扰我的是,IAsyncEnumerable方法如何知道如何只执行5次,或者换句话说,它如何翻译.Take(5)方法,使其可以获取传递的数字执行时考虑到?
IAsyncEnumerable<T>
是一个简单的接口,定义了单一方法 - IAsyncEnumerable<T>.GetAsyncEnumerator(CancellationToken)
返回IAsyncEnumerator<T>
,这并没有那么复杂 - 它有 MoveNextAsync
方法,可以将枚举器异步前进到下一个元素集合的 Current
属性,获取集合中枚举数当前位置的元素,类似于“普通”IEnumerable<T>
。简而言之,所有 LINQ 方法都将与这两个方法一起运行(如果我们不考虑对某些极端情况的优化)。
据我所知,没有框架为异步枚举提供 LINQ 方法。如果您使用的是 反应扩展
中的
System.Linq.Async
中的一个,那么它的实现方式与“普通”Take
基本相同,它将源枚举包装到具有重载的 MoveNext
的特殊“分区器”类中。对于异步枚举,它是 AsyncEnumerablePartition
,它基本上会调用 await MoveNextAsync(...)
,直到达到请求的限制(即传递到 Take
),然后停止执行。