0Pricing
C# Academy · Leçon

IAsyncEnumerable et await foreach

Diffusez les données de manière asynchrone avec IAsyncEnumerable, utilisez yield dans les itérateurs asynchrones et consommez-les avec await foreach.

IAsyncEnumerable et await foreach est une leçon C# Academy gratuite sur CoddyKit. Ceci est la leçon 1 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage C# Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours C# Academy comprend 4 leçons au total.

Pourquoi utiliser IAsyncEnumerable ?

IAsyncEnumerable<T> (introduit avec C# 8 et .NET Core 3) permet le flux asynchrone : vous fournissez les éléments un par un dès qu’ils sont disponibles, sans tout charger d’abord en mémoire. Imaginez la lecture ligne par ligne d’un curseur de base de données ou la transmission progressive de réponses d’API.

Écrire un itérateur asynchrone

Déclarez une méthode qui renvoie IAsyncEnumerable<T> et utilisez yield return dans une méthode asynchrone. Les mots-clés await et yield return coexistent naturellement.

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;
    }
}

Consommer avec await foreach

Consommez un IAsyncEnumerable<T> avec await foreach. Chaque itération attend le prochain élément de manière asynchrone : le consommateur et le producteur avancent naturellement au même rythme.

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);
}

Diffuser les résultats d’une base de données

EF Core prend en charge la diffusion des résultats de requête avec AsAsyncEnumerable(). Les lignes sont lues une par une sans charger l’ensemble des résultats en mémoire, ce qui est essentiel pour les grandes tables.

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;
    }
}

Diffuser des réponses HTTP

Diffusez les réponses volumineuses aux clients sans mettre en mémoire tampon l’intégralité de la charge utile. Le client reçoit progressivement les données pendant que le serveur poursuit son traitement.

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();
    }
});

L’annotation EnumeratorCancellation

Appliquez [EnumeratorCancellation] au paramètre CancellationToken d’un itérateur asynchrone afin que WithCancellation() du côté du consommateur transmette le jeton au producteur.

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 sur IAsyncEnumerable

Le package NuGet System.Linq.Async fournit des opérateurs LINQ asynchrones (WhereAwait, SelectAwait, ToListAsync) pour 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);

Fusionner plusieurs flux asynchrones

Pour traiter plusieurs flux asynchrones simultanément, utilisez Channel comme point de convergence : écrivez depuis plusieurs producteurs et lisez depuis un seul consommateur.

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;
}

Performances : mise en mémoire tampon ou diffusion

Diffusez toujours les données lorsque vous traitez de grands ensembles de données. Tout charger d’abord dans une liste (ToListAsync()) conserve toutes les données en mémoire simultanément ; la diffusion traite un élément à la fois.

// 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)

Gestion des erreurs dans les itérateurs asynchrones

Entourez l’intégralité de await foreach d’un bloc try/catch pour gérer les erreurs du producteur. Les erreurs de l’itérateur sont propagées au consommateur au point d’itération concerné.

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.");
}

Vérification rapide

Quel est le principal avantage d’IAsyncEnumerable en matière de mémoire par rapport au renvoi d’une List<T> ?

Récapitulatif : IAsyncEnumerable et await foreach

Points clés à retenir :

  • IAsyncEnumerable<T> : diffuse les éléments de manière asynchrone, un par un
  • yield return dans les méthodes asynchrones produit des itérateurs asynchrones
  • await foreach : consomme le flux avec annulation via .WithCancellation()
  • [EnumeratorCancellation] : transmet le jeton du consommateur à l’itérateur
  • EF Core : utilisez AsAsyncEnumerable() pour les grandes requêtes économes en mémoire
  • Traitement de grands ensembles de données : diffusez les éléments au lieu d’utiliser ToListAsync()

Questions Fréquemment Posées

La leçon « IAsyncEnumerable et await foreach » est-elle gratuite ?

Oui — le texte complet de « IAsyncEnumerable et await foreach » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours C# Academy, passe à CoddyKit PRO. Le cours C# Academy comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « IAsyncEnumerable et await foreach » ?

Diffusez les données de manière asynchrone avec IAsyncEnumerable, utilisez yield dans les itérateurs asynchrones et consommez-les avec await foreach. Tu pratiques C# Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer C# Academy ?

Aucune expérience préalable n'est requise. C# Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 1 sur 4.

Combien de temps prend la leçon « IAsyncEnumerable et await foreach » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon C# Academy ?

Oui. Chaque leçon C# Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. IAsyncEnumerable et await foreach
  2. System.Threading.Channels
  3. ValueTask et réduction des allocations
  4. ConfigureAwait et contexte de synchronisation
← Retour à C# Academy