IAsyncEnumerable og await foreach
Stream data asynkront med IAsyncEnumerable, brug yield i asynkrone iteratorer, og forbrug dem med await foreach.
IAsyncEnumerable og await foreach er en gratis C# Academy-lektion på CoddyKit. Dette er lektion 1 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i C# Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. C# Academy-kurset indeholder 4 lektioner i alt.
Hvorfor IAsyncEnumerable?
IAsyncEnumerable<T> (introduceret i C# 8 og .NET Core 3) muliggør asynkron datastrømning – du leverer elementer ét ad gangen, efterhånden som de bliver tilgængelige, uden først at indlæse alt i hukommelsen. Tænk på at læse rækker fra en database én ad gangen eller streame API-svar.
Skriv en asynkron iterator
Deklarér en metode, der returnerer IAsyncEnumerable<T>, og brug yield return inde i en asynkron metode. Nøgleordene await og yield return kan naturligt bruges sammen.
public async IAsyncEnumerable<int> GenerateNumbersAsync(int count)
{
for (int i = 0; i < count; i++)
{
await Task.Delay(100); // simulate async work per item
yield return i;
}
}Brug med await foreach
Forbrug en IAsyncEnumerable<T> med await foreach. Hver iteration venter asynkront på det næste element – producenten og forbrugeren tilpasser naturligt tempoet til hinanden.
await foreach (var number in GenerateNumbersAsync(10))
{
Console.WriteLine(number);
}
// With cancellation:
var cts = new CancellationTokenSource();
await foreach (var n in GenerateNumbersAsync(100)
.WithCancellation(cts.Token))
{
if (n > 50) { cts.Cancel(); break; }
Console.WriteLine(n);
}Datastrømning fra en database
EF Core understøtter datastrømning af forespørgselsresultater med AsAsyncEnumerable(). Det læser rækker én ad gangen uden at indlæse hele resultatsættet i hukommelsen – afgørende for store tabeller.
public async IAsyncEnumerable<Product> StreamProductsAsync(
[EnumeratorCancellation] CancellationToken ct = default)
{
await foreach (var product in _db.Products
.Where(p => p.IsActive)
.AsAsyncEnumerable()
.WithCancellation(ct))
{
yield return product;
}
}Datastrømning af HTTP-svar
Stream store svar til klienter uden at gemme hele nyttelasten i en buffer. Klienten modtager data løbende, mens serveren fortsætter behandlingen.
app.MapGet("/stream/products", (ProductRepository repo) =>
{
// Returns an IAsyncEnumerable — ASP.NET Core streams it as JSON array
return repo.StreamAllAsync();
});
// Or with custom serialization:
app.MapGet("/stream/events", async (HttpResponse response, EventStore store) =>
{
response.ContentType = "application/json";
await foreach (var e in store.StreamAsync())
{
await response.WriteAsJsonAsync(e);
await response.Body.FlushAsync();
}
});Attributten EnumeratorCancellation
Anvend [EnumeratorCancellation] på CancellationToken-parameteren i en asynkron iterator, så WithCancellation() på forbrugersiden fører tokenet videre til producenten.
public async IAsyncEnumerable<LogEntry> TailLogAsync(
string logFile,
[EnumeratorCancellation] CancellationToken ct = default)
{
while (!ct.IsCancellationRequested)
{
var newLines = await ReadNewLinesAsync(logFile, ct);
foreach (var line in newLines)
yield return new LogEntry(line);
await Task.Delay(500, ct);
}
}
// Consumer:
await foreach (var entry in TailLogAsync("/var/log/app.log")
.WithCancellation(cts.Token))
{
Console.WriteLine(entry.Message);
}LINQ over IAsyncEnumerable
NuGet-pakken System.Linq.Async leverer asynkrone LINQ-operatorer (WhereAwait, SelectAwait, ToListAsync) til IAsyncEnumerable.
// dotnet add package System.Linq.Async
var expensiveProducts = await repo.StreamAllAsync()
.WhereAwait(async p => await pricing.IsExpensiveAsync(p.Id))
.SelectAwait(async p => await enricher.EnrichAsync(p))
.Take(10)
.ToListAsync();
// Or use built-in Where/Select that don't need async:
var names = repo.StreamAllAsync()
.Where(p => p.IsActive)
.Select(p => p.Name);Sammenfletning af flere asynkrone datastrømme
Hvis flere asynkrone datastrømme skal behandles samtidigt, skal du bruge Channel som samlingspunkt – skriv fra flere producenter og læs fra én forbruger.
async IAsyncEnumerable<T> Merge<T>(
params IAsyncEnumerable<T>[] streams)
{
var channel = Channel.CreateUnbounded<T>();
var producers = streams.Select(async stream =>
{
await foreach (var item in stream)
await channel.Writer.WriteAsync(item);
});
_ = Task.WhenAll(producers)
.ContinueWith(_ => channel.Writer.Complete());
await foreach (var item in channel.Reader.ReadAllAsync())
yield return item;
}Ydeevne: bufferlagring kontra datastrømning
Brug altid datastrømning ved behandling af store datasæt. Hvis du først indlæser alt i en liste (ToListAsync()), ligger alle data samtidig i hukommelsen – datastrømning behandler ét element ad gangen.
// BAD: loads all 1M records into memory
var allOrders = await _db.Orders.ToListAsync();
foreach (var order in allOrders)
await ProcessAsync(order);
// GOOD: processes one record at a time
await foreach (var order in _db.Orders.AsAsyncEnumerable())
await ProcessAsync(order);
// Memory usage: O(1) vs O(n)Fejlhåndtering i asynkrone iteratorer
Indpak hele await foreach i en try/catch for at håndtere fejl fra producenten. Fejl i iteratoren føres videre til forbrugeren ved den aktuelle iteration.
try
{
await foreach (var item in RiskyStreamAsync())
{
await ProcessAsync(item);
}
}
catch (HttpRequestException ex)
{
Console.Error.WriteLine($"Stream error: {ex.Message}");
}
catch (OperationCanceledException)
{
Console.WriteLine("Stream cancelled.");
}Hurtig kontrol
Hvad er den primære fordel ved IAsyncEnumerable med hensyn til hukommelse sammenlignet med at returnere en List<T>?
Opsummering: IAsyncEnumerable og await foreach
Vigtigste læringspunkter:
IAsyncEnumerable<T>: stream elementer asynkront, ét ad gangenyield returni asynkrone metoder producerer asynkrone iteratorerawait foreach: forbrug datastrømmen med annullering via.WithCancellation()[EnumeratorCancellation]: fører forbrugerens token videre til iteratoren- EF Core: brug
AsAsyncEnumerable()til hukommelseseffektive forespørgsler på store datamængder - Behandling af store datasæt: brug datastrømning i stedet for
ToListAsync()
Lær C# med en AI-underviser — gratis
Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.
- Kurser
- 93
- Lektioner
- 346
Ofte stillede spørgsmål
Er lektionen “IAsyncEnumerable og await foreach” gratis?
Ja — hele teksten til “IAsyncEnumerable og await foreach” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af C# Academy-kurset, skal du opgradere til CoddyKit PRO. C# Academy-kurset indeholder 4 lektioner i alt.
Hvad lærer jeg i “IAsyncEnumerable og await foreach”?
Stream data asynkront med IAsyncEnumerable, brug yield i asynkrone iteratorer, og forbrug dem med await foreach. Du øver dig i C# Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.
Skal jeg have erfaring for at begynde på C# Academy?
Der kræves ingen tidligere erfaring. C# Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 1 af 4.
Hvor lang tid tager lektionen “IAsyncEnumerable og await foreach”?
De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.
Kan jeg skrive og køre kode i denne C# Academy-lektion?
Ja. Alle C# Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.
Alle lektioner i dette kursus
- IAsyncEnumerable og await foreach
- System.Threading.Channels
- ValueTask og undgåelse af allokeringer
- ConfigureAwait og synkroniseringskontekst