微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

IAsyncEnumerable<T> 和迭代器生成的 IEnumerable<Task<T>> 有什么区别?

如何解决IAsyncEnumerable<T> 和迭代器生成的 IEnumerable<Task<T>> 有什么区别?

我正在尝试找出 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();
}

这个类同时实现了 IAsyncEnumerable<int>IEnumerable<Task<int>>。我可以同时使用 await foreachforeach 对其进行迭代并得到相同的结果:

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);
}

两次迭代都显示数字 0 到 4,每行之间都有一秒的延迟。

唯一的优势是否与取消能力有关(即传入的 cancellationToken)?还是有一些我在这里没有看到的场景?

解决方法

等待一个数字序列,每个数字之间有一个定义的延迟

延迟发生在不同的时间。 IEnumerable<Task<T>> 立即返回下一个元素,然后该元素被 await ed。 IAsyncEnumerable<T> await 是下一个元素。

IEnumerable<Task<T>> 是一个(同步)枚举,其中每个元素都是异步的。当您有已知数量的操作要执行,然后每个项目独立异步到达时,这是使用的正确类型。

例如,这种类型通常用于同时发送多个 REST 请求。要发出的 REST 请求的数量在开始时是已知的,并且每个请求都被Select放入异步 REST 调用中。然后通常将生成的可枚举(或集合)传递给 await Task.WhenAll 以异步等待它们全部完成。

IAsyncEnumerable<T> 是一个异步枚举;即,its MoveNext is actually an asynchronous MoveNextAsync。当您有未知数量的项目要迭代并且获取下一个(或下一批)(可能)是异步的时,这是使用的正确类型。

例如,当分页结果来自 API 时,通常使用此类型。在这种情况下,您不知道最终会返回多少个元素。事实上,在检索下一页结果之前,您甚至可能不知道自己是否在最后。因此,即使确定是否存在 下一项也是异步操作。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?