异步流
异步流(asynchronous stream)是一种异步接收多个数据项的方式,其建立在异步枚举之上(IAsyncEnumerable<T>)。异步枚举是一种异步版本的枚举,也就是说,他可以依照使用者的要求异步生成数据项。
异步流和Task<T>
Task<T>的标准异步方法只足以应对异步处理单个数据值,一旦某个Task<T>完成,任务就结束了,单个Task<T>不能为其使用者提供多个T值。即使T是一个集合,该值也只能提供一次。
与Task<T>相比,异步流更类似于枚举,具体来说,IAsyncEnumerator<T>可以提供任意数量的T值,而且一次一个,和IEnumerator<T>一样,IAsyncEnumerator<T>可以是无现场的
异步流和IEnumerable<T>
IEnumerable<T>都会阻塞代码,IAsyEnumerable<T>会异步获取下一个元素。
#异步流和Task<IEnumerable<T>>
异步返回的集合完全可以包含多个数据项,Task<List
Task<IEnumerable<T>>的局限在于无法返回刚获取的数据项。如果返回集合,那么它必须把所有相都加在到内存中,填充该集合,然后一次性返回整个集合。即便它返回LINQ查询,并且可以异步构建该查询,但一经返回,该查询中的每一项也是同步获取的。IAsyncEnumerable<T>也会异步返回多个数据项,但区别在于,IAsyncEnumerable<T>可以针对返回的每一项执行异步操作,这是真正由数据项组成的异步流。
异步流和IObservable
可观察对象是真正的异步流概念,它一次生成多个通知,真正支持异步生产(无阻塞)。不过IObservable<T>的消耗方式与IAsyncEnumerable<T>截然不同。
类型 | 单值/多值 | 异步/同步 | 推拉/拉式 |
---|---|---|---|
T | 单值 | 同步 | 都不是 |
IEnumerable<T> | 多值 | 同步 | 都不是 |
Task<T> | 单值 | 异步 | 拉式 |
IAsyncEnumerable<T> | 多值 | 异步 | 拉式 |
IObservable<T> | 单值或多值 | 异步 | 推式 |
创建异步流
假设需要返回多个值,而且需要对每个值执行一些异步处理,下面的两种方法可以实现这个操作
– 通过IEnumerable<T> 返回多个值,然后对其进行异步处理。
– 通过Task<T>异步返回单个值,然后添加其他的返回值
通过yield return 可以从一个方法返回多个值,而异步方法使用async和await。