前端开发:不写样式代码才是最好的写样式方式
2026/3/18 15:18:50
在异步编程日益重要的当下,处理大量数据的异步操作时,高效的迭代方式至关重要。IAsyncEnumerable<T>应运而生,为异步迭代提供了简洁且强大的解决方案。深入研究它,有助于开发者编写出性能卓越、资源利用高效的异步代码。
IEnumerable<T>在处理异步操作时,会导致线程阻塞,影响应用程序的响应性。IAsyncEnumerable<T>通过异步迭代,允许在迭代过程中挂起和恢复,提高资源利用率和程序的整体性能。IAsyncEnumerable<T>采用异步迭代模式,它允许在迭代过程中暂停操作,等待异步操作(如I/O操作)完成后再继续,而不会阻塞调用线程。IEnumerable<T>类似,IAsyncEnumerable<T>也是延迟执行的。只有当开始迭代时,才会真正执行相关的异步操作,避免不必要的资源消耗。IAsyncEnumerable<T>接口定义了GetAsyncEnumerator方法,用于获取一个IAsyncEnumerator<T>对象。IAsyncEnumerator<T>接口继承自IAsyncDisposable,除了常规的MoveNextAsync和Current属性外,还提供了异步释放资源的能力。publicinterfaceIAsyncEnumerable<outT>{IAsyncEnumerator<T>GetAsyncEnumerator(CancellationTokencancellationToken=default);}publicinterfaceIAsyncEnumerator<outT>:IAsyncDisposable{ValueTask<bool>MoveNextAsync();TCurrent{get;}}GetAsyncEnumerator获取枚举器后,通过反复调用MoveNextAsync方法推进迭代。MoveNextAsync返回一个ValueTask<bool>,true表示还有数据,false表示迭代结束。在MoveNextAsync内部,可能会执行异步操作(如异步I/O),并在操作完成后返回结果。usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Threading;usingSystem.Threading.Tasks;classProgram{staticasyncIAsyncEnumerable<int>GenerateNumbersAsync(){for(inti=0;i<5;i++){awaitTask.Delay(1000);yieldreturni;}}staticasyncTaskMain(){awaitforeach(varnumberinGenerateNumbersAsync()){Console.WriteLine($"Received number:{number}");}}}GenerateNumbersAsync方法使用async IAsyncEnumerable<int>声明,通过yield return逐一生成数据,并使用await Task.Delay模拟异步操作。Main方法中使用await foreach异步迭代数据。usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Threading;usingSystem.Threading.Tasks;classProgram{staticasyncIAsyncEnumerable<int>GenerateNumbersAsync(){for(inti=0;i<10;i++){awaitTask.Delay(500);yieldreturni;}}staticasyncTaskMain(){varsum=awaitGenerateNumbersAsync().WhereAsync(n=>n%2==0).SumAsync();Console.WriteLine($"Sum of even numbers:{sum}");}staticasyncIAsyncEnumerable<T>WhereAsync<T>(thisIAsyncEnumerable<T>source,Func<T,Task<bool>>predicate){awaitforeach(variteminsource){if(awaitpredicate(item)){yieldreturnitem;}}}staticasyncTask<int>SumAsync(thisIAsyncEnumerable<int>source){intsum=0;awaitforeach(varnumberinsource){sum+=number;}returnsum;}}GenerateNumbersAsync生成数字序列。WhereAsync和SumAsync扩展方法实现异步过滤和聚合操作。Main方法先对生成的数字序列进行异步过滤,再计算总和。usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Threading;usingSystem.Threading.Tasks;classProgram{staticasyncIAsyncEnumerable<int>GenerateNumbersWithErrorAsync(){for(inti=0;i<5;i++){if(i==3){thrownewInvalidOperationException("Simulated error");}awaitTask.Delay(1000);yieldreturni;}}staticasyncTaskMain(){awaitforeach(varnumberinGenerateNumbersWithErrorAsync()){Console.WriteLine($"Received number:{number}");}}}await foreach块中正确捕获异常。usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Threading;usingSystem.Threading.Tasks;classProgram{staticasyncIAsyncEnumerable<int>GenerateNumbersWithErrorAsync(){for(inti=0;i<5;i++){if(i==3){thrownewInvalidOperationException("Simulated error");}awaitTask.Delay(1000);yieldreturni;}}staticasyncTaskMain(){try{awaitforeach(varnumberinGenerateNumbersWithErrorAsync()){Console.WriteLine($"Received number:{number}");}}catch(InvalidOperationExceptionex){Console.WriteLine($"Caught exception:{ex.Message}");}}}Main方法使用try - catch块捕获GenerateNumbersWithErrorAsync中抛出的异常,避免异常未处理导致程序崩溃。IAsyncEnumerable<T>在处理异步I/O操作时,能显著提升性能,因为它不会阻塞线程。在内存使用上,由于是逐块处理数据,内存占用也更为合理,尤其是处理大量数据时。例如,在从数据库异步读取10万条记录时,同步迭代可能会导致内存瞬间飙升,而异步迭代可将内存占用控制在较低水平,QPS也能保持较高数值。MoveNextAsync中包含过多复杂的同步操作,尽量保持异步特性。IAsyncEnumerator<T>实现中,确保正确释放资源,尤其是在异常情况下。await foreach块中始终做好异常处理,防止未处理异常导致程序崩溃。IAsyncEnumerable<T>用于异步迭代,支持在迭代过程中暂停等待异步操作,不会阻塞线程;而IEnumerable<T>是同步迭代,在迭代过程中会阻塞线程直到操作完成。yield return时按照分页规则返回数据。例如,async IAsyncEnumerable<int> GenerateNumbersPaginatedAsync(int offset, int count)。IAsyncEnumerable<T>是.NET异步编程中的重要工具,其核心在于异步迭代和延迟执行。适用于处理异步数据源和大量数据的场景,但在处理简单同步数据时可能会增加代码复杂度。随着.NET的不断发展,预计会进一步优化其性能和易用性,为异步编程提供更强大的支持。