异步编程已经流行很多年了,.NET 引入的 async 和 await 关键词让异步编程更具有可读性,但有一个遗憾,在 C# 8 之前都不能使用异步的方式处理数据流,直到 C# 8 引入的 IAsyncEnumerable<T> 才解决了这个问题。

说到 IAsyncEnumerable<T> ,得先说一说 IEnumerable<T> ,大家都知道,它是用同步的方式来迭代 collection 集合的,而这里的 IAsyncEnumerable<T> 则是用异步方式,换句话说: IAsyncEnumerable<T> 在迭代集合的过程中不会阻塞调用线程。

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<T> 模式,很遗憾的是,这种方式没有扩展性,因为它是需要阻塞调用线程的。

最好的解决方案就是 return yield + 返回值 IAsyncEnumerable<T> 模式,异步迭代器方法返回的是 IAsyncEnumerable<T>实例,并且可以包含一个或多个 yield return 语句。

在 C#8 中创建异步迭代器

下面的代码片段展示了一个返回 Task<IEnumerable<T>> 类型的异步方法,如下代码所示:


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<T>,它可以让你应用程序代码更干净,更高效 和 更高性能。

更多精彩,欢迎订阅

译文链接:https://www.infoworld.com/article/3531251/how-to-use-asynchronous-streams-in-csharp-80.html

C# 8 中的异步迭代器 IAsyncEnumerable<T> 解析的更多相关文章

  1. 一文说通C#中的异步迭代器

    今天来写写C#中的异步迭代器 - 机制.概念和一些好用的特性   迭代器的概念 迭代器的概念在C#中出现的比较早,很多人可能已经比较熟悉了. 通常迭代器会用在一些特定的场景中. 举个例子:有一个for ...

  2. 深入Asyncio(八)异步迭代器

    Async Iterators: async for 除了async def和await语法外,还有一些其它的语法,本章学习异步版的for循环与迭代器,不难理解,普通迭代器是通过__iter__和__ ...

  3. [译]Python中的异步IO:一个完整的演练

    原文:Async IO in Python: A Complete Walkthrough 原文作者: Brad Solomon 原文发布时间:2019年1月16日 翻译:Tacey Wong 翻译时 ...

  4. 【JS】336- 拆解 JavaScript 中的异步模式

    点击上方"前端自习课"关注,学习起来~ JavaScript 中有很多种异步编程的方式.callback.promise.generator.async await 甚至 RxJS ...

  5. 【JS】285- 拆解 JavaScript 中的异步模式

    JavaScript 中有很多种异步编程的方式.callback.promise.generator.async await 甚至 RxJS.我最初接触不同的异步模式时,曾想当然的觉得 promise ...

  6. ASP.NET MVC EF 中使用异步控制器

    最近悟出来一个道理,在这儿分享给大家:学历代表你的过去,能力代表你的现在,学习代表你的将来. 十年河东十年河西,莫欺少年穷 学无止境,精益求精   为什么使用异步操作/线程池 ASP.NET MVC ...

  7. NodeJS中的异步I/O、事件驱动

    nodejs的主要特点是单线程.异步I/O.事件驱动.让我们先大概了解一下这些名词的意思. 单线程 单线程是任务按照顺序执行的,并且每次只执行一个任务,只有前面的任务执行完成以后,后面的任务才执行.在 ...

  8. C#中的线程一(委托中的异步)

    C#中的线程一(委托中的异步) 一.同步委托 我们平时所用的委托以同步居多,我们编写一个方法和相关委托进行演示: publicdelegatevoid DoSomethingDelegate(stri ...

  9. 看stackoverflow大牛如何回答何时在ASP.NET中使用异步控制器?

    转载自博客园:http://farb.cnblogs.com/ 今天无意中看到stackoverflow上一个很好的问答,个人觉得很有价值,所以翻译过来和大家共享!希望大家能相互交流. 在ASP.NE ...

随机推荐

  1. OAuth2授权流程

  2. set CSS style in js solutions All In One

    set CSS style in js solutions All In One css in js set each style property separately See the Pen se ...

  3. Github Actions All In One

    Github Actions All In One https://github.com/features/actions https://github.com/marketplace?type=ac ...

  4. 以代码为剑、数学为犁,SPC构建NGK算力生态体系

    人类创造工具,工具反过来也改变着人类.以区块链为核心的货币革命率先吹响了对金融世界重塑的号角.以代码为剑.数学为犁,区块链构建了新的网路信任体系,这是一切的开始.基于此,NGK区块链技术将赋能实体产业 ...

  5. elasticsearch如何设计索引

    本文为博客园作者所写: 一寸HUI,个人博客地址:https://www.cnblogs.com/zsql/ 最近在做es相关的工作,所以记录下自己的一些想法,可能很多方面不会很全面,但是基本都是经过 ...

  6. 三万长文50+趣图带你领悟web编程的内功心法:一文带你深入解读HTTP的发展史

    看到题目,大家是不是认为根据上一篇(两万字长文50+张趣图带你领悟网络编程的内功心法)一样,其实不然,我们上一边介绍的是网络编程的基本功,有了这些基本功之后,我们就可以在此之上构建更加接近实际应用的w ...

  7. Scrapy项目_苏宁图书信息

     苏宁图书(https://book.suning.com/) 目标: 1.图书一级分类 2.图书二级分类 3.图书三级分类 4.图书名字 5.图书作者 6.图书价格 7.通过Scrapy获取以上数据 ...

  8. 从几个问题开始理解CFS调度器

    本文转载自从几个问题开始理解CFS调度器 导语 CFS(完全公平调度器)是Linux内核2.6.23版本开始采用的进程调度器,它的基本原理是这样的:设定一个调度周期(sched_latency_ns) ...

  9. css优先级和权重

    1. 权重概念: 权重,是一个相对的概念,是针对某一指标而言.某一指标的权重是指该指标在整体评价中的相对重要程度. 权重系数,是表示某一指标项在指标项系统中的重要程度,它表示在其它指标项不变的情况下, ...

  10. winform程序post提交数据API

    工作经验  备忘 //API接口 using (var Client = new HttpClient())                 { Client.BaseAddress = new Ur ...