#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