什么是IAsyncEnumerable
IAsyncEnumerable<T>
是 .NET 中用于表示异步数据流的接口。
它允许你逐个异步地获取数据项,而不是将所有数据一次性加载到内存中。这样可以减少内存占用,尤其在处理大量数据时更加高效。
与 IEnumerable<T>
不同,IEnumerable<T>
是同步的,要求所有数据在返回之前就加载完成。
而 IAsyncEnumerable<T>
是异步的,支持在数据流被请求时逐步加载,适合处理从数据库或网络等源异步获取的数据。
示例:
public async IAsyncEnumerable<int> GetNumbersAsync()
{
for (int i = 0; i < 10; i++)
{
await Task.Delay(100); // 模拟异步操作
yield return i;
}
}
好处
减少内存占用:IAsyncEnumerable<T>
逐步加载数据,避免了需要将所有数据一次性加载到内存中。对于大数据量的查询,能显著减少内存压力。
提升响应性能:在 WebAPI 中,返回 IAsyncEnumerable<T>
可以让客户端在获取部分数据时立即开始处理,而无需等待所有数据都加载完成。这使得响应时间更短,提升用户体验。
避免阻塞操作:使用 async/await
使得 WebAPI 不会被同步阻塞操作所拖慢,能够更好地处理并发请求。
以 WebAPI + EFCore 举例
假设我们需要通过 Entity Framework Core 从数据库中查询大量记录。
如果我们一次性加载所有数据,可能会导致内存占用过高,甚至影响性能。使用 IAsyncEnumerable<T>
,我们可以逐个获取数据。
示例代码:
public class ProductController : ControllerBase
{
private readonly ApplicationDbContext _context;
public ProductController(ApplicationDbContext context)
{
_context = context;
}
[HttpGet("products")]
public async IAsyncEnumerable<Product> GetProductsAsync()
{
await foreach (var product in _context.Products.AsAsyncEnumerable())
{
yield return product;
}
}
}
在这个例子中,AsAsyncEnumerable()
方法将 DbSet<Product>
转换成一个异步数据流,await foreach
循环逐个从数据库中异步获取数据并返回,避免了内存占用过多。
以 WebAPI + HTTPClient 举例
在 WebAPI 中,你可能需要调用其他服务或外部 API 来获取数据。使用 IAsyncEnumerable<T>
可以使得调用返回的数据逐步加载,避免等待整个请求完成后再返回。
示例代码:
public class ExternalApiController : ControllerBase
{
private readonly HttpClient _httpClient;
public ExternalApiController(HttpClient httpClient)
{
_httpClient = httpClient;
}
[HttpGet("external-data")]
public async IAsyncEnumerable<string> GetExternalDataAsync()
{
var response = await _httpClient.GetAsync("https://api.example.com/data");
response.EnsureSuccessStatusCode();
var stream = await response.Content.ReadAsStreamAsync();
using (var reader = new StreamReader(stream))
{
string? line;
while ((line = await reader.ReadLineAsync()) != null)
{
yield return line;
}
}
}
}
在这个例子中,我们通过 HTTPClient 请求外部 API 数据,并使用 IAsyncEnumerable<string>
返回每一行数据,允许客户端逐步处理数据,而无需等待所有数据都加载完毕。
需使用System.Text.Json格式化程序。 使用Newtonsoft.Json或XML-based格式化程序时,会缓冲结果,造成最后一次返回。
客户端怎么处理 IAsyncEnumerable<T>
客户端接收到 IAsyncEnumerable<T>
数据流后,可以使用异步迭代器 await foreach
来逐步处理数据。
这样可以在数据流逐步传输过程中及时处理和显示数据,而不必等待全部数据加载完成。
C# 客户端代码:
public class ProductClient
{
private readonly HttpClient _httpClient;
public ProductClient(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task GetProductsAsync()
{
var products = _httpClient.GetFromJsonAsAsyncEnumerable("https://api.example.com/data");
await foreach (var p in products)
{
Console.WriteLine(DateTime.Now.ToString() + " " + p.Id);
}
}
}
JavaScript 客户端处理:
在 JavaScript 中,客户端可以使用 fetch
API 和流(Streams)来逐步处理数据。WebAPI 返回的数据流可以通过 Response.body.getReader()
来读取并逐步消费。
async function fetchProducts() {
const response = await fetch('https://example.com/products');
const reader = response.body.getReader();
const decoder = new TextDecoder();
let done = false;
let value = '';
while (!done) {
const { done: chunkDone, value: chunk } = await reader.read();
done = chunkDone;
value += decoder.decode(chunk, { stream: true });
console.log(value); // 逐步输出数据
}
}
通过上述方式,JavaScript 客户端可以逐步处理 WebAPI 返回的异步流,提升用户体验和响应速度。
![](https://images.cnblogs.com/cnblogs_com/chenyishi/1348350/o_240408130234_wx.png)
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 本地部署 DeepSeek:小白也能轻松搞定!
· 传国玉玺易主,ai.com竟然跳转到国产AI
· 自己如何在本地电脑从零搭建DeepSeek!手把手教学,快来看看! (建议收藏)
· 我们是如何解决abp身上的几个痛点
· 如何基于DeepSeek开展AI项目