当前位置: 首页 > 科技观察

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

时间:2023-03-14 14:59:23 科技观察

本文转载请联系码农阅读公众号。异步编程已经流行了很多年。.NET引入的async和await关键字让异步编程更具可读性,但遗憾的是在C#8之前无法以异步方式处理数据流,直到C#8IAsyncEnumerable的引入解决了这个问题。说到IAsyncEnumerable,就不得不先说说IEnumerable。大家都知道它是以同步的方式迭代collection集合,而这里的IAsyncEnumerable使用的是异步方式。换句话说:IAsyncEnumerable不会阻塞调用线程。IAsyncDisposable、IAsyncEnumerable、IAsyncEnumerator异步流允许我们以异步方式处理数据。在此之前,我们需要了解以下三个接口:IAsyncDisposable、IAsyncEnumerable和IAsyncEnumerator,它们都在.NETStandard2.1,以下代码片段显示了这三个接口的定义。publicinterfaceIAsyncDisposable{ValueTaskDisposeAsync();}publicinterfaceIAsyncEnumerable{IAsyncEnumeratorGetAsyncEnumerator(CancellationTokentoken=default);}publicinterfaceIAsyncEnumerator:IAsyncDisposable{ValueTaskMoveNextAsync}rrent{;想象一下,您有一个数据访问层,需要一次从数据库中读取所有数据。该功能的使用非常简单,直接调用底层提供的异步方法XXXAsyc即可实现异步调用,一次性返回所有数据。只要不是所有的数据都呈现在页面上,这个方案问题不大。在很多情况下,更多的是采用分页阅读的形式。事实上,当数据可用时,还有另一种更好的方法可以做到这一点。立即返回给调用者。准确的说,可以使用异步流来解决这个问题。如果你的方法是同步返回的,可以使用returnyield+returnvalueIEnumerable方式。不幸的是,这种方法没有可扩展性,因为它需要阻塞调用线程。最好的解决方案是返回yield+返回值IAsyncEnumerable模式。异步流方法返回一个IAsyncEnumerable实例,并且可以包含一个或多个yieldreturn语句。在C#8中创建异步流以下代码片段显示了一个返回TaskclassProgram{constintDELAY=1000;constintMIN=1;constintMAX=10;publicstaticasyncTaskMain(string[]args){foreach(intnumberinawaitGetData()){Console.WriteLine($"{DateTime.Now}:number={number}");}Console.ReadLine();}publicstaticasyncTask>GetData(){Listintegers=newList();for(inti=MIN;i<=MAX;i++){awaitTask.Delay(DELAY);integers.Add(i);}returnintegers;}}当运行上述应用程序时,它会等待10s,然后将所有1-10添加到数字输出控制台上,虽然这个GetData是异步的,但是是一次性输出,而不是每一秒一个一个输出。这时候可以让yield关键字介入。它是在C#2.0中引入的。它通常用于执行状态迭代并从集合中逐一返回数据。您不需要像上面那样创建一个集合(整数)并返回它。,下面的代码片段是修改了GetData方法并合并了yield关键字的版本。代码如下:staticasyncIAsyncEnumerableGetData(){for(inti=MIN;iGetData(){for(inti=MIN;i