Как вырваться из IAsyncEnumerable при итерации?
В C# 8 добавлена поддержка асинхронных блоков итераторов, поэтому вы можете ждать и возвращать IAsyncEnumarator
вместо IEnumerable
:
public async IAsyncEnumerable<int> EnumerateAsync() {
for (int i = 0; i < 10; i++) {
yield return i;
await Task.Delay(1000);
}
}
С неблокирующим кодом, который выглядит следующим образом:
await foreach (var item in EnumerateAsync()) {
Console.WriteLine(item);
}
Это приведет к тому, что мой код будет работать около 10 секунд. Однако иногда я хочу вырваться из await foreach
до того, как все элементы потребляются. С break
Тем не менее, нам нужно подождать, пока ток не ожидается Task.Delay
закончил Как мы можем немедленно выйти из этого цикла, не ожидая каких-либо висячих асинхронных задач?
1 ответ
Использование CancellationToken
это решение, так как это единственное, что может отменить Task.Delay
в вашем коде. То, как мы получаем это в вашем IAsyncEnumerable
это передать его в качестве параметра при его создании, поэтому давайте сделаем это:
public async IAsyncEnumerable<int> EnumerateAsync(CancellationToken cancellationToken = default) {
for (int i = 0; i < 10; i++) {
yield return i;
await Task.Delay(1000, cancellationToken);
}
}
С потребляющей стороны:
// In this example the cancellation token will be caneled after 2.5 seconds
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(2.5));
await foreach (var item in EnumerateAsync(cts.Token)) {
Console.WriteLine(item);
}
Конечно, это отменит перечисление после того, как 3 элемента были возвращены, но закончится TaskCanceledException
выброшенный из Task.Delay
, Изящно выйти из await foreach
мы должны поймать это и сломать на стороне производства:
public async IAsyncEnumerable<int> EnumerateAsync(CancellationToken cancellationToken = default) {
for (int i = 0; i < 10; i++) {
yield return i;
try {
await Task.Delay(1000, cancellationToken);
} catch (TaskCanceledException) {
yield break;
}
}
}
Заметка
На данный момент это все еще в предварительном просмотре и может быть изменено. Если вы заинтересованы в этой теме, вы можете посмотреть обсуждение языковой команды C# о CancellationToken
в IAsyncEnumeration
,