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

如何判断ForEachAsync执行完成?gRpc流式调用场景下的实现问题

实现方案

你当前代码中直接用_ =丢弃了ForEachAsync返回的Task对象,因此无法监听遍历的完成状态,只要保留该Task并监听其状态即可实现需求:
ForEachAsync本身返回的就是Task类型,该Task运行完成时就代表流式返回的所有元素已经遍历处理完毕(包括服务端主动结束流、触发取消、调用报错三种结束场景)。

代码修改示例

如果你需要等所有元素遍历完成后再执行后续操作,直接await这个Task即可:

private async Task UpdateProgress(string id)
{
    CancellationTokenSource cts = new CancellationTokenSource();
    ProgressServiceClient progressClient = new ProgressServiceClient(progressServerAddress);
    ChannelName channelName = new ChannelName() { Id = id };

    var timestamp = Timestamp.FromDateTime(DateTime.UtcNow);

    // 保留ForEachAsync返回的Task,不要丢弃
    var processTask = progressClient.ProgressReports(channelName)
    .ForEachAsync((x) =>
    {
        if (timestamp < x.TimeStamp)
        {
            UpdateRow(x);
        }
    }, cts.Token);
   
    this.Dispatcher.Invoke(() =>
    {
        if (cts != null && !cts.IsCancellationRequested)
        {
            Application.Current.Exit += (_, __) => cts.Cancel();
            this.Unloaded += (_, __) => cts.Cancel();
        }
    });
    
    // 等待遍历结束,执行到此处就代表所有元素处理完成/触发取消/出现异常
    try
    {
        await processTask;
        // 这里写遍历完成后要执行的后续业务逻辑
    }
    catch (OperationCanceledException)
    {
        // 处理主动取消的场景:比如页面卸载、程序退出时触发的取消
    }
    catch (Exception ex)
    {
        // 处理流式调用异常:比如网络中断、服务端报错等场景
    }
}

其他场景说明

如果你不需要同步等待遍历完成,希望先执行其他逻辑,之后再判断遍历是否结束,可以通过Task的属性直接判断状态:

  • processTask.IsCompleted:为true代表遍历已经结束(包含正常结束、取消、异常三种情况)
  • processTask.IsCompletedSuccessfully:为true代表所有元素正常遍历处理完毕,没有触发取消也没有报错
  • processTask.IsCanceled:为true代表遍历被CancellationToken主动取消
  • processTask.IsFaulted:为true代表遍历过程中抛出了异常

另外你原代码末尾的await Task.Delay(50)没有实际业务作用,可以直接删除。

内容的提问来源于stack exchange,提问作者baerlein

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 16:54:01