IAsyncEnumerable能否按Task完成顺序返回结果?
实现并行Task的IAsyncEnumerable按返回顺序输出结果
完全可以实现你的需求——让所有REST API调用Task并行执行,然后按任务完成的顺序逐个yield结果。核心思路是借助Task.WhenAny持续等待已完成的任务,配合yield return输出结果。
核心实现代码
假设你的REST API调用方法返回Task<ApiResult>,以下是实现方法:
public async IAsyncEnumerable<ApiResult> ProcessParallelTasksAsync(List<Task<ApiResult>> tasks) { // 用HashSet存储剩余任务,方便快速移除已完成项 var remainingTasks = new HashSet<Task<ApiResult>>(tasks); while (remainingTasks.Count > 0) { // 等待任意一个任务完成 var completedTask = await Task.WhenAny(remainingTasks); // 从剩余列表中移除已完成任务,避免重复处理 remainingTasks.Remove(completedTask); // 获取结果并返回(await已完成任务不会阻塞) yield return await completedTask; } }
使用说明
提前启动所有任务:确保传入的Task列表已经启动执行,否则会变成串行执行。比如:
// 批量创建并启动10个API调用任务 var apiTasks = Enumerable.Range(1, 10) .Select(taskId => CallRestApiAsync(taskId)) .ToList(); // 遍历结果,按任务完成顺序处理 await foreach (var result in ProcessParallelTasksAsync(apiTasks)) { Console.WriteLine($"收到结果:任务{result.TaskId}返回数据"); }异常处理:如果某个API调用抛出异常,
await completedTask会触发异常,可按需添加捕获逻辑:try { yield return await completedTask; } catch (HttpRequestException ex) { // 返回错误结果或记录日志 yield return new ApiResult { TaskId = -1, Error = $"API调用失败:{ex.Message}" }; }
原理说明
Task.WhenAny会返回第一个完成的Task,保证我们能优先处理最快返回的结果- 每次处理完已完成的任务后,从剩余集合中移除,避免重复处理
IAsyncEnumerable的yield return特性允许我们逐个返回结果,无需等待所有任务完成
内容的提问来源于stack exchange,提问作者FeeFiFoFum
相关产品推荐
相关产品推荐

