本文转载自微信公众号「码农读书」,作者码农读书。转载本文请联系码农读书公众号。
异步编程已经流行很多年了,.NET 引入的 async 和 await 关键词让异步编程更具有可读性,但有一个遗憾,在 C# 8 之前都不能使用异步的方式处理数据流,直到 C# 8 引入的 IAsyncEnumerable
说到 IAsyncEnumerable
IAsyncDisposable, IAsyncEnumerable<T>, IAsyncEnumerator<T>
异步流 允许我们可以用异步的方式处理数据,在这之前要了解下面三个接口:IAsyncDisposable, IAsyncEnumerable<T> 和 IAsyncEnumerator<T>,他们都是在 .NET Standard 2.1 中被引入,下面的代码片段展示了这三个接口的定义。
- public interface IAsyncDisposable
- {
- ValueTask DisposeAsync();
- }
- public interface IAsyncEnumerable<out T>
- {
- IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken
- token = default);
- }
- public interface IAsyncEnumerator<out T> : IAsyncDisposable
- {
- ValueTask<bool> MoveNextAsync();
- T Current { get; }
- }
为什么要使用异步流
可以想象一下你有一个数据访问层需要从数据库中一次性读取所有的数据,要想使用这个功能很简单,可以直接调用 底层提供的异步方法 XXXAsyc 实现异步调用并且一次性返回所有数据。
只要不是将所有数据都呈现在页面上的话,这种解决方案问题不是太大,很多时候更多的是通过 分页读取 的形式,其实在这方面还有一个比较好的做法就是在数据可用时立即返回给调用者。
准确的说,这里可使用 异步流 的方式来解决,如果你的方法是同步返回的话,你可以使用 return yield + 返回值 IEnumerable
最好的解决方案就是 return yield + 返回值 IAsyncEnumerable
在 C#8 中创建异步流
下面的代码片段展示了一个返回 Task
- class Program
- {
- const int DELAY = 1000;
- const int MIN = 1;
- const int MAX = 10;
- public static async Task Main(string[] args)
- {
- foreach (int number in await GetData())
- {
- Console.WriteLine($"{DateTime.Now}: number={number}");
- }
- Console.ReadLine();
- }
- public static async Task<IEnumerable<int>> GetData()
- {
- List<int> integers = new List<int>();
- for (int i = MIN; i <= MAX; i++)
- {
- await Task.Delay(DELAY);
- integers.Add(i);
- }
- return integers;
- }
- }
当运行上面的应用程序,它会等待 10s 之后再将所有的 1-10 的数字输出控制台上,虽然这个 GetData 是异步的,但最终还是一次性输出了,而不是一个一个的隔秒输出。
这个时候可以让 yield 关键词介入,它是在 C# 2.0 中被引入的,常用于执行状态迭代 并且按一个一个的从集合中返回数据,你不需要像上面一样创建一个集合(integers) 再返回上去,下面的代码片段是修改 GetData 方法并且合并了 yield 关键词的版本,代码如下:
- static async IAsyncEnumerable<int> GetData()
- {
- for (int i = MIN; i < MAX; i++)
- {
- yield return i;
- await Task.Delay(DELAY);
- }
- }
C#8 中使用异步流
要想使用异步流, 需要在 foreach 前增加一个 await 关键词,如下代码所示:
- public static async Task Main(string[] args)
- {
- await foreach (int number in GetData())
- {
- Console.WriteLine($"{DateTime.Now}: number={number}");
- }
- Console.ReadLine();
- }
下面是完整的仅供参考的代码。
- class Program
- {
- const int DELAY = 1000;
- const int MIN = 1;
- const int MAX = 10;
- public static async Task Main(string[] args)
- {
- await foreach (int number in GetData())
- {
- Console.WriteLine($"{DateTime.Now}: number={number}");
- }
- Console.ReadLine();
- }
- static async IAsyncEnumerable<int> GetData()
- {
- for (int i = MIN; i < MAX; i++)
- {
- yield return i;
- await Task.Delay(DELAY);
- }
- }
- }
C# 8 中一个非常重要的特性就是支持了 IAsyncEnumerable
译文链接:https://www.infoworld.com/article/3531251/how-to-use-asynchronous-streams-in-csharp-80.html
Docker生成新镜像版本的两种方式 There are two ways Docker can generate new m...
建站 什么 虚拟主机 够用?这要看搭建的是什么类型的网站。比如个人博客类型的网...
在Python语言中有如下3种方法: 成员方法 类方法(classmethod) 静态方法(staticm...
从 10.0.0 版开始,异步迭代器就出现在 Node 中了,在本文中,我们将讨论异步迭...
2021年3月24日,主题为《数据的世界,世界的数据》的星环科技2021春季新品发布会...
【51CTO.com快译】 数据可视化工具不断发展,提供更强大的功能,同时改善可访问...
摘要 元旦期间 订单业务线 告知 推送系统 无法正常收发消息,作为推送系统维护者...
信息化2.0时代提出开展智慧教育创新发展行动。2019年2月,中共中央、国务院印发...
本文整理自直播《Hologres 数据导入/导出实践-王华峰(继儒)》 视频链接: https:/...
前提条件 请您在购买前确保已完成注册和充值。详细操作请参见 如何注册公有云管...