You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
    }
}

使用说明

  1. 提前启动所有任务:确保传入的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}返回数据");
    }
    
  2. 异常处理:如果某个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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 04:15:42