IAsyncEnumerable och await foreach
Strömma data asynkront med IAsyncEnumerable, använd yield i asynkrona iteratorer och konsumera med await foreach.
IAsyncEnumerable och await foreach är en gratis lektion i C# Academy på CoddyKit. Detta är lektion 1 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för C# Academy, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i C# Academy innehåller totalt 4 lektioner.
Varför IAsyncEnumerable?
IAsyncEnumerable<T> (introducerades i C# 8 och .NET Core 3) möjliggör asynkron strömning — objekt lämnas ut ett i taget när de blir tillgängliga, utan att allt först behöver läsas in i minnet. Tänk på att läsa rader från en databaskursor en i taget eller att strömma API-svar.
Skriva en asynkron iterator
Deklarera en metod som returnerar IAsyncEnumerable<T> och använd yield return i en asynkron metod. Nyckelorden await och yield return fungerar naturligt tillsammans.
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;
}
}Förbrukning med await foreach
Förbruka en IAsyncEnumerable<T> med await foreach. Varje iteration väntar asynkront på nästa objekt — konsument och producent håller automatiskt samma tempo.
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);
}Strömning från en databas
EF Core stöder strömning av frågeresultat med AsAsyncEnumerable(). Raderna läses en i taget utan att hela resultatmängden läses in i minnet — vilket är avgörande för stora 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;
}
}Strömning av HTTP-svar
Strömma stora svar till klienter utan att buffra hela nyttolasten. Klienten tar emot data fortlöpande medan servern fortsätter bearbetningen.
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();
}
});Attributet EnumeratorCancellation
Använd [EnumeratorCancellation] på parametern CancellationToken i en asynkron iterator så att WithCancellation() på konsumentsidan för vidare token till 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 över IAsyncEnumerable
NuGet-paketet System.Linq.Async tillhandahåller asynkrona LINQ-operatorer (WhereAwait, SelectAwait, ToListAsync) för 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);Sammanfogning av flera asynkrona strömmar
För att bearbeta flera asynkrona strömmar samtidigt kan Channel användas som en fan-in-samlingspunkt — skriv från flera producenter och läs från en enda konsument.
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;
}Prestanda: buffring kontra strömning
Strömma alltid när stora datamängder bearbetas. Om allt först läses in i en lista (ToListAsync()) hålls all data samtidigt i minnet — med strömning bearbetas ett objekt i taget.
// 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)Felhantering i asynkrona iteratorer
Omslut hela await foreach med try/catch för att hantera fel från producenten. Fel i iteratorn vidarebefordras till konsumenten vid den aktuella iterationen.
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.");
}Snabbtest
Vilken är den främsta minnesfördelen med IAsyncEnumerable jämfört med att returnera en List
Repetition: IAsyncEnumerable och await foreach
Viktiga slutsatser:
IAsyncEnumerable<T>: strömma objekt asynkront, ett i tagetyield returni asynkrona metoder skapar asynkrona iteratorerawait foreach: förbruka strömmen med avbrytning via.WithCancellation()[EnumeratorCancellation]: vidarebefordrar konsumentens token till iteratorn- EF Core: använd
AsAsyncEnumerable()för minneseffektiva stora frågor - Bearbeta stora datamängder genom att strömma i stället för att använda
ToListAsync()
Lär dig C# med en AI-lärare – gratis
Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.
- Kurser
- 93
- Lektioner
- 346
Vanliga frågor
Är lektionen ”IAsyncEnumerable och await foreach” gratis?
Ja – hela texten till ”IAsyncEnumerable och await foreach” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i C# Academy, kan Ni uppgradera till CoddyKit PRO. Kursen i C# Academy innehåller totalt 4 lektioner.
Vad lär jag mig i ”IAsyncEnumerable och await foreach”?
Strömma data asynkront med IAsyncEnumerable, använd yield i asynkrona iteratorer och konsumera med await foreach. Ni övar på C# Academy med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.
Behöver jag någon erfarenhet för att börja lära mig C# Academy?
Du behöver inga förkunskaper. Utbildningen i C# Academy på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 1 av 4.
Hur lång tid tar lektionen ”IAsyncEnumerable och await foreach”?
De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.
Kan jag skriva och köra kod i den här C# Academy-lektionen?
Ja. Varje C# Academy-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.
Alla lektioner i den här kursen
- IAsyncEnumerable och await foreach
- System.Threading.Channels
- ValueTask och undvika allokeringar
- ConfigureAwait och synkroniseringskontext