如何在 C# 8 中使用 异步流

本文转载自微信公众号「码农读书」,作者码农读书。转载本文请联系码农读书公众号。

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

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

IAsyncDisposable, IAsyncEnumerable,  IAsyncEnumerator

异步流 允许我们可以用异步的方式处理数据,在这之前要了解下面三个接口:IAsyncDisposable, IAsyncEnumerable 和 IAsyncEnumerator,他们都是在 .NET Standard 2.1 中被引入,下面的代码片段展示了这三个接口的定义。

 
 
 
 
  1. public interface IAsyncDisposable 
  2.     ValueTask DisposeAsync(); 
  3.  
  4. public interface IAsyncEnumerable 
  5.     IAsyncEnumerator GetAsyncEnumerator(CancellationToken 
  6.     token = default); 
  7.  
  8. public interface IAsyncEnumerator : IAsyncDisposable 
  9.     ValueTask MoveNextAsync(); 
  10.     T Current { get; } 

为什么要使用异步流

可以想象一下你有一个数据访问层需要从数据库中一次性读取所有的数据,要想使用这个功能很简单,可以直接调用 底层提供的异步方法 XXXAsyc 实现异步调用并且一次性返回所有数据。

只要不是将所有数据都呈现在页面上的话,这种解决方案问题不是太大,很多时候更多的是通过 分页读取 的形式,其实在这方面还有一个比较好的做法就是在数据可用时立即返回给调用者。

准确的说,这里可使用 异步流 的方式来解决,如果你的方法是同步返回的话,你可以使用 return yield + 返回值 IEnumerable 模式,很遗憾的是,这种方式没有扩展性,因为它是需要阻塞调用线程的。

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

在 C#8 中创建异步流

下面的代码片段展示了一个返回 Task

 
 
 
 
  1. class Program 
  2.  { 
  3.      const int DELAY = 1000; 
  4.      const int MIN = 1; 
  5.      const int MAX = 10; 
  6.  
  7.      public static async Task Main(string[] args) 
  8.      { 
  9.          foreach (int number in await GetData()) 
  10.          { 
  11.              Console.WriteLine($"{DateTime.Now}: number={number}"); 
  12.          } 
  13.  
  14.          Console.ReadLine(); 
  15.      } 
  16.  
  17.      public static async Task> GetData() 
  18.      { 
  19.          List integers = new List(); 
  20.          for (int i = MIN; i <= MAX; i++) 
  21.          { 
  22.              await Task.Delay(DELAY); 
  23.              integers.Add(i); 
  24.          } 
  25.          return integers; 
  26.      } 
  27.  } 

当运行上面的应用程序,它会等待 10s 之后再将所有的 1-10 的数字输出控制台上,虽然这个 GetData 是异步的,但最终还是一次性输出了,而不是一个一个的隔秒输出。

这个时候可以让 yield 关键词介入,它是在 C# 2.0 中被引入的,常用于执行状态迭代 并且按一个一个的从集合中返回数据,你不需要像上面一样创建一个集合(integers) 再返回上去,下面的代码片段是修改 GetData 方法并且合并了 yield 关键词的版本,代码如下:

 
 
 
 
  1. static async IAsyncEnumerable GetData() 
  2.    for (int i = MIN; i < MAX; i++) 
  3.    { 
  4.       yield return i; 
  5.       await Task.Delay(DELAY);   
  6.    } 

C#8 中使用异步流

要想使用异步流, 需要在 foreach 前增加一个 await 关键词,如下代码所示:

 
 
 
 
  1. public static async Task Main(string[] args) 
  2.         { 
  3.             await foreach (int number in GetData()) 
  4.             { 
  5.                 Console.WriteLine($"{DateTime.Now}: number={number}"); 
  6.             } 
  7.  
  8.             Console.ReadLine(); 
  9.         } 

下面是完整的仅供参考的代码。

 
 
 
 
  1. class Program 
  2.    { 
  3.        const int DELAY = 1000; 
  4.        const int MIN = 1; 
  5.        const int MAX = 10; 
  6.  
  7.        public static async Task Main(string[] args) 
  8.        { 
  9.            await foreach (int number in GetData()) 
  10.            { 
  11.                Console.WriteLine($"{DateTime.Now}: number={number}"); 
  12.            } 
  13.  
  14.            Console.ReadLine(); 
  15.        } 
  16.  
  17.        static async IAsyncEnumerable GetData() 
  18.        { 
  19.            for (int i = MIN; i < MAX; i++) 
  20.            { 
  21.                yield return i; 
  22.                await Task.Delay(DELAY); 
  23.            } 
  24.        } 
  25.    } 

C# 8 中一个非常重要的特性就是支持了 IAsyncEnumerable ,它可以让你应用程序代码更干净,更高效 和 更高性能。

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

分享题目:如何在 C# 8 中使用 异步流
本文来源:http://www.mswzjz.cn/qtweb/news24/358474.html

攀枝花网站建设、攀枝花网站运维推广公司-贝锐智能,是专注品牌与效果的网络营销公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 贝锐智能