NET Core 3.0和C# 8.0最激动人心的特性之一就是IAsyncEnumerable<T>(也就是async流)。但它有什么特别之处呢?我们现在可以用它做哪些以前不可能做到的事?

在本文中,我们将了解IAsyncEnumerable<T>要解决哪些挑战,如何在我们自己的应用程序中实现它,以及为什么IAsyncEnumerable<T>将在很多情况下取代Task<IEnumerable<T>>。

也许最好的证明IAsyncEnumerable < T >有用的方式是看看在没有它的时候所面临的的困难。

比如首先有这样一段代码,按页面获取所有喜欢的帖子:

 public async Task<IEnumerable<Post>> GetPagePostsFromLikes(int pageNumber)
{
// 实现省略
}
public async Task<IEnumerable<Post>> GetAllPostsFromLikes()
{
var allPosts = new List<Post>(); for (int page = 0; ; page++)
{
var posts = await GetPagePostsFromLikes(page);
if (!posts.Any())
{
return allPosts;
}
allPosts.AddRange(posts);
}
}

注意,上面这个方法有一个问题,我们对每个页面的结果进行循环并放入List<Post>中,最后返回整个结果。假设有上亿个page页面的的帖子,那么所有这上亿个page页面的帖子都需要在返回值之前被加载。显然是非常低效的。

也许我们可以不使用Task来替换上面的方法:

public IEnumerable<Post> GetAllPostsFromLikes()
{
for (int page = 0; ; page++)
{
var posts = GetPagePostsFromLikes(page).GetAwaiter().GetResult();
if (!posts.Any())
{
yield break;
}
foreach (var post in posts)
{
yield return post;
}
}
}

在上面代码中,返回IEnumerable<T>的方法可以使用yield return语句将每个数据片段返回给调用者。

但是,请勿这样做! 上面的代码意味着如果我们从异步方法中调用第三个函数,线程池将持续迭代返回的IEnumerable,直到其完成,也就是说当有足够多的并发访问同一个线程,势必会造成阻塞。

如果我们可以用异步方法来使用yield return就好了!可惜那是不可能的……直到现在。

 这个时候IAsyncEnumerable<T> 就该出场啦!!!!!!

IAsyncEnumerable<T>是在.NET Core 3 (.NET Standard 2.1)引入的。它公开了一个枚举器,该枚举器具有可以等待的MoveNextAsync()方法。这意味着生产者可以在产生结果之间进行异步调用。

与返回任务<IEnumerable<T>>不同,我们的方法现在可以返回IAsyncEnumerable<T>,并使用yield return来发送数据:

public async IAsyncEnumerable<Post> GetAllPostsFromLikes()
{
for (int page = 0; ; page++)
{
var posts = GetPagePostsFromLikes(page).GetAwaiter().GetResult();
if (!posts.Any())
{
yield break;
}
foreach (var post in posts)
{
yield return post;
}
}
}

为了使用结果,我们需要使用c# 8中新的await foreach()语法:

await foreach (var post in postsRepository.GetAllPostsFromLikes())
{
Console.WriteLine(post);
}

当然可以使用扩展

public static async Task<List<T>> AsListAsync<T>(this IAsyncEnumerable<T> source, CancellationToken cancellationToken = default)
{
var list = new List<T>();
await foreach (var item in source.WithCancellation(cancellationToken).ConfigureAwait(false))
{
list.Add(item);
} return list;
}

从.NET Core 3.0 Preview 7 开始,ASP.NET就能够从API控制器动作中返回IAsyncEnumerable<T>,这意味着我们可以直接返回方法的结果——有效地将数据从数据库流到HTTP响应。

     [HttpGet]
public IAsyncEnumerable<Post> Get()
=> postsRepository.GetAllPostsFromLikes();

随着时间的推移,随着.NET Core3.0和.NET Standard2.1的发展,我们将会看到IAsyncEnumerable<T>被用在我们通常使用Task<IEnumerable<T>>的地方。

总结

IAsyncEnumerable<T>是. net的一个很受欢迎的新特性,在很多情况下,它可以使代码更简洁、更高效。

想要了解更多,请参考以下资源:

如果你要在Linq中使用s ystem.Linq.Async在System.Reactive包的名称空间中。如果您不需要完整的System.Reactive软件包,则可以直接使用System.Linq.Async软件包(是的一部分System.Reactive)。
您可以阅读此github问题。的来源System.Linq.Async可以在这里找到。

首先安装Nuget

github https://github.com/dotnet/reactive 得lx.Async 得system.linq.async

最新文章

  1. 你应该知道的jQuery技巧 [转]
  2. 使用nbrbutil工具來處理requested media id is in use, cannot process request
  3. 容器的范围 .xml
  4. ANativeWindow是个什么东西
  5. Session 原理
  6. Sublime Text 3配置记录
  7. c语言中细节注意(初级)
  8. Struts文件上传
  9. Dynamics CRM OData方式进行增删改查时报错的问题
  10. 13、属性的get(存)和set(取)器
  11. 使用echart 做出数据折线图
  12. 每一行代码都有记录—如何用git一步步探索项目的历史
  13. p4364 [九省联考2018]IIIDX
  14. pcl文档库
  15. Boost application performance using asynchronous I/O-ref
  16. ToolBar 简单使用
  17. Python基础学习之字符串(1)
  18. 补充——a.extend(b) #合并列表——a.update(b) #把b字典的元素加入到a字典里面
  19. [SCOI2010]连续攻击游戏 BZOJ1854 二分图匹配
  20. EntityFramework codefirst

热门文章

  1. 【原创】视频+文字:详解VBA解决数独问题
  2. 解决YUM下Loaded plugins: fastestmirror Determining fastest mirrors 的错误问题
  3. 杂篇-之裸眼3D渲染相机及画面矫正
  4. Nebula Flink Connector 的原理和实践
  5. HPSocket介绍与使用
  6. Python使用import导入模块时执行了模块的文件但报ModuleNotFoundError错误的愚蠢问题
  7. 第14.10节 Python中使用BeautifulSoup解析http报文:html标签相关属性的访问
  8. PyQt(Python+Qt)学习随笔:布局控件layout的LeftMargin等contentsMargins属性
  9. PostMan设置环境变量&amp;全局变量
  10. 将ACCESS 的数据库中的表的文件 导出了EXCEL格式