C# 8.0中,提供了一种新的IAsyncEnumerable<T>接口,在对集合进行迭代时,支持异步操作。比如在读取文本中的多行字符串时,如果读取每行字符串的时候使用同步方法,那么会导致线程堵塞。IAsyncEnumerable<T>可以解决这种情况,在迭代的时候支持使用异步方法。也就是说,之前我们使用foreach来对IEnumerable进行迭代,现在可以使用await foreach来对IAsyncEnumerable<T>进行迭代,每个项都是可等待的。这种新的接口称为async-streams,将会随.NET Core 3发布。我们来看一下如何在LINQ中实现异步的迭代。

使用常规的IEnumerable<T>

首先我们创建一个新的Console项目,基于.NET Core 3

这是一个很简单的Console程序,实现了一个简单的返回类型为IEnumerable<string>ReadAllLines(string file)方法,从文本文件中逐行读取文本,并逐行输出。如果文本内容较少的话,没什么问题。但如果我们使用过aync/await,就会了解,在IO操作如读取或写入文件的时候,最好使用异步方法以避免线程阻塞。让我们来改进一下。

使用异步的IAsyncEnumerable<T>

可以优化的是下面这句:

对于IO操作,最好使用异步方式。这里可使用相应的异步方法:

我们说“异步是传染的”,如果这里使用异步,那么相应的该方法的返回值也要使用异步,所以需要将返回值改为static async Task<IEnumerable<string>>,但这样会得到一个错误:

因为Task<IEnumerable<string>>并不是一个可以迭代的接口类型,所以我们无法在方法内部使用yield关键字。解决问题的办法是使用新的IAsyncEnumerable接口:

F12查看该接口的定义:

这是一个异步的迭代器,并提供了CancellationToken。再按F12查看IAsyncEnumerator<T>的定义,可发现里面是这样的:

这里MoveNextAsync()方法实际是返回了一个结果类型为boolTask,每次迭代都是可等待的,从而实现了迭代器的异步。

使用await foreach消费IAsyncEnumerable<T>

当我们做了以上改动之后,ReadAllLines()方法返回的是一个支持异步的IAsyncEnumerable,那么在使用的时候,也不能简单的使用foreach了。修改Main方法如下:

首先在foreach之前添加await关键字,还要需要将Main方法由void改为async Task。这样整个程序都是异步执行了,不会再导致堵塞了。这个例子只是一个简单的demo,是否使用异步并不会感觉到明显的区别。如果在迭代内部需要比较重的操作,如从网络获取大量数据或读取大量磁盘文件,异步的优势还是会比较明显的。

使用LINQ消费IAsyncEnumerable<T>

使用LINQ来操作集合是常用的功能。如果使用IEnumberable,在Main方法中可以做如下改动:

或:

如果使用了新的IAsyncEnumerable,你会发现无法使用Where等操作符了:

目前LINQ还没有提供对IAsyncEnumerable的原生支持,不过微软提供了一个Nuget包来实现此功能。在项目中打开Nuget Package Manger搜索安装System.Linq.Async,注意该包目前还是预览版,所以要勾选include prerelease才能看到。安装该Nuget包后,Linq查询语句中的错误就消失了。

System.Linq.Async这个包中,对每个同步的LINQ方法都做了相应的扩展。所以基本上代码无需什么改动即可正常编译。

对于LINQ中的条件语句,也可以使用WhereAwait()方法来支持await

如需要在条件语句中进行IO或网络请求等异步操作,可以这样用:

DoSomeHeavyOperationsAsync方法的签名如下:

小结

通过以上的示例,我们简要了解了如何使用IAsyncEnumerable接口以及如何在LINQ中实现异步查询。在使用该接口时,我们需要创建一个自定义方法返回IAsyncEnumerable<T>来代替IEnumberable<T>,这个方法可称为async-iterator方法,需要注意以下几点:

  • 该方法应该被声明为async

  • 返回IAsyncEnumerable<T>

  • 同时使用awaityield。如await foreachyield returnyield break等。

例如:

此外还有一些限制:

  • 无法在tryfinally块中使用任何形式的yield语句。

  • 无法在包含任何catch语句的try语句中使用yield return语句。

期待.NET Core 3的正式发布!

点个赞再走呗?

C#8.0: 在 LINQ 中支持异步的 IAsyncEnumerableT接口相关推荐

  1. [转]使用 .NET Framework 2.0 在您的应用程序中支持证书

    NET 安全 使用 .NET Framework 2.0 在您的应用程序中支持证书 Dominick Baier 本文讨论: Windows 证书存储区 .NET 中的证书类 验证.SSL.Web 服 ...

  2. HTTP3快来了,提前学习一下如何在Nginx中支持HTTP3.0/QUIC

    HTTP3快来了,提前学习一下如何在Nginx中支持HTTP3.0/QUIC HTTP3.0,也称作HTTP over QUIC.核心是QUIC(读音quick)协议,由Google在2015年提出的 ...

  3. 在Nginx中支持HTTP3.0/QUIC

    在Nginx中支持HTTP3.0/QUIC HTTP3.0,也称作HTTP over QUIC.核心是QUIC(读音quick)协议,由Google在2015年提出的SPDY v3演化而来的新协议,传 ...

  4. 在 VMware ESXi 5.5 和 6.0.x 中支持大于 2 TB 的虚拟机磁盘 (2058287)

    Purpose 免责声明:本文为 Support for virtual machine disks larger than 2 TB in VMware ESXi 5.5 and 6.0.x (20 ...

  5. .NET Core 3.0 Preview 3中关于ASP.NET Core的更新内容

    .NET Core 3.0 Preview 3已经推出,它包含了一系列关于ASP.NET Core的新的更新. 下面是该预览版的更新列表: Razor组件改进: 单项目模板 新的Razer扩展 End ...

  6. java grpc 服务路由_.NET Core 3.0 Preview 3中关于ASP.NET Core的更新内容

    原标题:.NET Core 3.0 Preview 3中关于ASP.NET Core的更新内容 英文:devblogs.microsoft.com 来源:艾心 译文:cnblogs.com/ediso ...

  7. android 6.0 自定义application,Android6.0之App中的资源管理对象创建

    Android与资源管理相关的类Resouces和AssetManager很有必要清楚他们的创建过程. 与资源查找与加载操作相关的类 资源查找与加载主要是靠Android资源管理框架来完成的,而And ...

  8. 服务化改造实践 | 如何在 Dubbo 中支持 REST

    什么是 REST REST 是 Roy Thomas Fielding [[1]](#fn1) 在 2000 年他的博士论文 [[2]](#fn2) "架构风格以及基于网络的软件架构设计&q ...

  9. .NET Core 3.0 Preview 6中对ASP.NET Core和Blazor的更新

    我们都知道在6月12日的时候微软发布了.NET Core 3.0的第6个预览版.针对.NET Core 3.0的发布我们国内的微软MVP-汪宇杰还发布的官翻版的博文进行了详细的介绍.具体的可以关注&q ...

最新文章

  1. python mock_Python中使用mock.Mock()进行mock测试
  2. 只读副本和Spring Data第4部分:配置只读存储库
  3. linux下sublime安装目录在那,linux下sublime text 3安装到配置
  4. AliOS Things声源定位应用演示 1
  5. 前端笔记-对webpack和vue的基本认识
  6. github快速通道
  7. hdu.1429.胜利大逃亡(续)(bfs + 0101011110)
  8. 浅谈SQL SERVER的备份还原模式
  9. SwiftUI实战三:创建List视图和导航Navigation
  10. matlab计算天线方向性系数,天线方向图(Antenna Pattern)的设计解析思路
  11. Sql server 双机热备份数据库
  12. 云流化云渲染技术在vr看房/装修领域是怎样实现的?
  13. 【实战篇】40 # 如何实现3D地球可视化?
  14. 【Codeforces Round #439 (Div. 2) A】The Artful Expedient
  15. Android中list常用方法,Android中的常用控件及其基本用法
  16. PHP学习-3 端口开放
  17. Hadoop多个文件单词计数
  18. 1989-字符串分割
  19. 2017互联网十大未解之谜,你能回答几个?
  20. 【车辆管理系统——开题报告 分享(仅供参考呀)】

热门文章

  1. Linux关机、重启命令
  2. python 中的os模块
  3. /hgfs下无共享文件夹?/mnt下没有hgfs文件夹?vmhgfs-fuse:找不到命令?
  4. WebApi的调用-3.Basic验证
  5. 李洪强iOS开发之- 实现简单的弹窗
  6. T-SQL利用Row_Number函数实现分页
  7. 27个赢得别人欣赏的诀窍
  8. 基于电子邮件的InfoPath表单发布的注意点 [Infopath 2007]
  9. Linux和Windows下部署BeetleX服务网关
  10. .NET6之MiniAPI(十一):本地化