Xen*_*ate 3 c# yield-return iasyncenumerable
我正在尝试找出带来IAsyncEnumerable<T>诸如IEnumerable<Task<T>>.
我编写了以下类,它允许我等待一系列数字,每个数字之间有定义的延迟:
class DelayedSequence : IAsyncEnumerable<int>, IEnumerable<Task<int>> {
readonly int _numDelays;
readonly TimeSpan _interDelayTime;
public DelayedSequence(int numDelays, TimeSpan interDelayTime) {
_numDelays = numDelays;
_interDelayTime = interDelayTime;
}
public IAsyncEnumerator<int> GetAsyncEnumerator(CancellationToken cancellationToken = default) {
async IAsyncEnumerable<int> ConstructEnumerable() {
for (var i = 0; i < _numDelays; ++i) {
await Task.Delay(_interDelayTime, cancellationToken);
yield return i;
}
}
return ConstructEnumerable().GetAsyncEnumerator();
}
public IEnumerator<Task<int>> GetEnumerator() {
IEnumerable<Task<int>> ConstructEnumerable() {
for (var i = 0; i < _numDelays; ++i) {
yield return Task.Delay(_interDelayTime).ContinueWith(_ => i);
}
}
return ConstructEnumerable().GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
Run Code Online (Sandbox Code Playgroud)
该类同时实现IAsyncEnumerable<int>和IEnumerable<Task<int>>。await foreach我可以使用and对其进行迭代foreach并获得相同的结果:
var delayedSequence = new DelayedSequence(5, TimeSpan.FromSeconds(1d));
await foreach (var i in delayedSequence) {
Console.WriteLine(i);
}
foreach (var t in delayedSequence) {
Console.WriteLine(await t);
}
Run Code Online (Sandbox Code Playgroud)
两次迭代都显示数字 0 到 4,每行之间有一秒的延迟。
唯一的优点是与取消功能有关(即传入的cancellationToken)吗?还是有一些我在这里没有看到的场景?
等待一系列数字,每个数字之间有定义的延迟
延迟发生在不同的时间。IEnumerable<Task<T>>立即返回下一个元素,然后对其进行awaited。IAsyncEnumerable<T> awaits 下一个元素。
IEnumerable<Task<T>>是一个(同步)枚举,其中每个元素都是异步的。当您有已知数量的要执行的操作并且每个项目独立异步到达时,这是正确的类型。
例如,这种类型通常在同时发送多个 REST 请求时使用。要发出的 REST 请求的数量在开始时就已知,并且每个请求都被Select编入异步 REST 调用。然后,通常将生成的枚举(或集合)传递给await Task.WhenAll异步等待它们全部完成。
IAsyncEnumerable<T>是一个异步枚举;即,它MoveNext实际上是一个异步的MoveNextAsync。当您有未知数量的要迭代的项目,并且获取下一个(或下一批)(可能)是异步的时,这是正确的类型。
例如,当从 API 分页结果时,通常使用此类型。在这种情况下,您不知道最终会返回多少元素。事实上,在检索下一页结果之前,您甚至可能不知道自己是否已到达最后。所以即使判断是否有下一项也是异步操作。