Как определить, когда ForEachAsync завершается?

#c# #asynchronous #grpc

Вопрос:

Я использую потоковую передачу gRPC, и мне нужно сообщить, когда в цикле ForEachAsync заканчиваются элементы, чтобы я мог сделать что-то еще. Как бы я это сделал?

Вот мой метод, содержащий цикл:

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

            _ = progressClient.ProgressReports(channelName)
            .ForEachAsync((x) =>
            {
                if (timestamp < x.TimeStamp)
                {
                    UpdateRow(x);
                }
            }, cts.Token);
           
            this.Dispatcher.Invoke(() =>
            {
                if (cts != null amp;amp; !cts.IsCancellationRequested)
                {
                    Application.Current.Exit  = (_, __) => cts.Cancel();
                    this.Unloaded  = (_, __) => cts.Cancel();
                }
            });
            await Task.Delay(50);
        }
 

Комментарии:

1. Ожидать возвращенную задачу вместо того, чтобы отбрасывать ее?

2. Как предлагает @JohanDonne или проверяя задачу. IsCompleted , если вы хотите проверить это на более позднем этапе.

3. Я пробовал это. Кажется, что он никогда не завершается, если не вызвать отмену токена отмены.

4. В этом случае вам следует проверить ProgressReports метод и выяснить, почему он никогда не возвращается.

5. После проведения дополнительных исследований в gRPC, кажется, что природа потока заключается в том, чтобы оставаться открытым до отмены, и поэтому цикл никогда не возвращается.

Ответ №1:

Вам нужно подождать, прежде чем foreach:

 await progressClient.ProgressReports(channelName)
            .ForEachAsync((x) =>
            {
                if (timestamp < x.TimeStamp)
                {
                    UpdateRow(x);
                }
            }, cts.Token);

// all the items returned here proceed with your changes
 

Нет необходимости назначать его где угодно, так как вы ничего не делаете с результатом.

В приведенной здесь статье содержится хорошее объяснение отсутствия ожидания при выполнении асинхронных задач: https://docs.microsoft.com/en-us/dotnet/visual-basic/language-reference/error-messages/bc42358