C# Academy · Lektion

IAsyncEnumerable och await foreach

Strömma data asynkront med IAsyncEnumerable, använd yield i asynkrona iteratorer och konsumera med await foreach.

Lektion 1 av 412 steg

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 taget
  • yield return i asynkrona metoder skapar asynkrona iteratorer
  • await 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()
Gratis att börja

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

  1. IAsyncEnumerable och await foreach
  2. System.Threading.Channels
  3. ValueTask och undvika allokeringar
  4. ConfigureAwait och synkroniseringskontext
← Tillbaka till C# Academy