C# IAsyncEnumerable Linq使用
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的一个很受欢迎的新特性,在很多情况下,它可以使代码更简洁、更高效。
想要了解更多,请参考以下资源:
- Tutorial: Generate and consume async streams using C# 8.0 and .NET Core 3.0
- C# language proposals - Async Streams
- new features in .NET Core 3
- https://docs.microsoft.com/en-us/archive/msdn-magazine/2019/november/csharp-iterating-with-async-enumerables-in-csharp-8
如果你要在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
最新文章
- 你应该知道的jQuery技巧 [转]
- 使用nbrbutil工具來處理requested media id is in use, cannot process request
- 容器的范围 .xml
- ANativeWindow是个什么东西
- Session 原理
- Sublime Text 3配置记录
- c语言中细节注意(初级)
- Struts文件上传
- Dynamics CRM OData方式进行增删改查时报错的问题
- 13、属性的get(存)和set(取)器
- 使用echart 做出数据折线图
- 每一行代码都有记录—如何用git一步步探索项目的历史
- p4364 [九省联考2018]IIIDX
- pcl文档库
- Boost application performance using asynchronous I/O-ref
- ToolBar 简单使用
- Python基础学习之字符串(1)
- 补充——a.extend(b) #合并列表——a.update(b) #把b字典的元素加入到a字典里面
- [SCOI2010]连续攻击游戏 BZOJ1854 二分图匹配
- EntityFramework codefirst
热门文章
- 【原创】视频+文字:详解VBA解决数独问题
- 解决YUM下Loaded plugins: fastestmirror Determining fastest mirrors 的错误问题
- 杂篇-之裸眼3D渲染相机及画面矫正
- Nebula Flink Connector 的原理和实践
- HPSocket介绍与使用
- Python使用import导入模块时执行了模块的文件但报ModuleNotFoundError错误的愚蠢问题
- 第14.10节 Python中使用BeautifulSoup解析http报文:html标签相关属性的访问
- PyQt(Python+Qt)学习随笔:布局控件layout的LeftMargin等contentsMargins属性
- PostMan设置环境变量&;全局变量
- 将ACCESS 的数据库中的表的文件 导出了EXCEL格式