• .NET Core 3.0中IAsyncEnumerable<T>有什么大不了的?


    .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);
                }

    这个好多了。该方法生成可用的数据。调用代码以自己的节奏使用数据。

    从.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的一个很受欢迎的新特性,在很多情况下,它可以使代码更简洁、更高效。

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

  • 相关阅读:
    03-架构设计的目的
    02-架构设计的历史背景
    01-架构到底是指什么
    python 基础 1.5 python数据类型(四)--字典
    python 基础 1.5 python数据类型(三)--元组常用方法示例
    python 基础 1.5 python数据类型(三)--元组
    python 基础 1.5 python数据类型(二)--列表常用方法示例
    python 基础 1.5 数据类型(二)--列表
    python 基础 1.5 python 数据类型(一)--整型 浮点型 布尔型及字符串和常用方法
    python 基础 1.4 python运算符
  • 原文地址:https://www.cnblogs.com/yixuanhan/p/11691303.html
Copyright © 2020-2023  润新知