0Pricing
Swift Academy · Leçon

Producteur/consommateur, pipelines et délais d’attente

Créez un modèle simple de producteur/consommateur , composez des pipelines avec AsyncSequence et implémentez un délai d’attente en mettant en concurrence une tâche de veille.

Producteur/consommateur, pipelines et délais d’attente est une leçon Swift Academy gratuite sur CoddyKit. Ceci est la leçon 1 sur 3. 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 Swift Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Swift Academy comprend 3 leçons au total.

Ce que vous allez construire

Cette leçon présente trois modèles :

  • Producteur/consommateur avec AsyncStream
  • Chaînes de traitement utilisant des transformations d’AsyncSequence
  • Délais d’expiration en mettant des tâches en concurrence de manière coopérative

Producteur/consommateur de base

AsyncStream relie les producteurs de style push à une consommation de type pull avec for await.

// Producer pushes values; consumer iterates them asynchronously.
func makeNumbers(count: Int) -> AsyncStream<Int> {
    AsyncStream { continuation in
        Task {
            for i in 1...count {
                continuation.yield(i)
                try? await Task.sleep(nanoseconds: 40_000_000) // ~40ms
            }
            continuation.finish()
        }
    }
}

Task {
    let stream = makeNumbers(count: 5)
    for await n in stream {
        print("consume:", n)
    }
    print("done") // after finish()
}

Politique de contre-pression

Choisissez une bufferingPolicy pour gérer la contre-pression (rejeter les éléments les plus anciens, les plus récents ou utiliser une capacité illimitée pour les petits flux).

// Use a limited buffering policy to avoid memory spikes.
func makeBufferedNumbers(limit: Int) -> AsyncStream<Int> {
    AsyncStream(bufferingPolicy: .bufferingOldest(limit)) { cont in
        Task {
            for i in 1...20 {
                cont.yield(i)
                // Producer is fast; buffer prevents unbounded growth
            }
            cont.finish()
        }
    }
}

Task {
    let s = makeBufferedNumbers(limit: 5)
    for await n in s {
        // Simulate a slow consumer
        try? await Task.sleep(nanoseconds: 60_000_000)
        print("got:", n)
    }
}

Chaîne de traitement avec AsyncSequence

AsyncSequence prend en charge des opérateurs familiers (map, filter, reduce) afin de construire clairement des chaînes de traitement en continu.

// Compose a pipeline: map -> filter -> reduce over an AsyncSequence.
func numbers(_ n: Int) -> AsyncStream<Int> {
    AsyncStream { cont in
        Task {
            for i in 1...n { cont.yield(i) }
            cont.finish()
        }
    }
}

Task {
    let evensSquaredSum = await numbers(10)
        .map { $0 * $0 }
        .filter { $0.isMultiple(of: 2) }
        .reduce(0, +)
    print("sum:", evensSquaredSum) // 220 (4+16+36+64+100)
}

Étape parallèle

Utilisez des groupes de tâches dans les chaînes de traitement pour les transformations exigeant beaucoup de calculs du CPU, puis fusionnez les résultats dans l’ordre que vous préférez.

// Fan-out/fan-in: process items concurrently, then merge.
// Here we use a task group to transform elements in parallel.
func parallelUppercased(_ input: [String]) async -> [String] {
    await withTaskGroup(of: String.self) { group in
        for s in input {
            group.addTask {
                try? await Task.sleep(nanoseconds: 30_000_000)
                return s.uppercased()
            }
        }
        return await group.reduce(into: [String]()) { $0.append($1) }
    }
}

Task {
    let out = await parallelUppercased(["a","bb","ccc"])
    print(out) // ["A","BB","CCC"]
}

Fonction utilitaire de délai d’expiration

Implémentez un délai d’expiration en mettant l’opération en concurrence avec une tâche sleep ; annulez la tâche perdante pour éviter de gaspiller du travail.

enum TimeoutError: Error { case timedOut }

func withTimeout<T>(
    seconds: Double,
    operation: @escaping () async throws -> T
) async throws -> T {
    try await withThrowingTaskGroup(of: T.self) { group in
        // Child 1: actual work
        group.addTask { try await operation() }
        // Child 2: the timer
        group.addTask {
            try await Task.sleep(nanoseconds: UInt64(seconds * 1_000_000_000))
            throw TimeoutError.timedOut
        }
        // First child to finish wins; cancel the rest
        let result = try await group.next()!
        group.cancelAll()
        return result
    }
}

// Demo
func slowFetch() async throws -> String {
    try await Task.sleep(nanoseconds: 300_000_000) // 300ms
    return "OK"
}

Task {
    do {
        let v = try await withTimeout(seconds: 0.1) { try await slowFetch() }
        print("value:", v)
    } catch {
        print("timeout:", error) // expected
    }
}

Modèle de délai d’expiration (course)

Vérification rapide : quelle est une bonne manière d’ajouter un délai d’expiration ?

Récapitulatif

Récapitulatif :

  • Utilisez AsyncStream pour le modèle producteur/consommateur.
  • Composez des chaînes de traitement AsyncSequence avec map/filter/reduce.
  • Implémentez les délais d’expiration en mettant des tâches en concurrence et en annulant la tâche perdante.

Questions Fréquemment Posées

La leçon « Producteur/consommateur, pipelines et délais d’attente » est-elle gratuite ?

Oui — le texte complet de « Producteur/consommateur, pipelines et délais d’attente » 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 Swift Academy, passe à CoddyKit PRO. Le cours Swift Academy comprend 3 leçons au total.

Qu'est-ce que j'apprendrai dans « Producteur/consommateur, pipelines et délais d’attente » ?

Créez un modèle simple de producteur/consommateur , composez des pipelines avec AsyncSequence et implémentez un délai d’attente en mettant en concurrence une tâche de veille. Tu pratiques Swift 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 Swift Academy ?

Aucune expérience préalable n'est requise. Swift 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 3.

Combien de temps prend la leçon « Producteur/consommateur, pipelines et délais d’attente » ?

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 Swift Academy ?

Oui. Chaque leçon Swift 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. Producteur/consommateur, pipelines et délais d’attente
  2. Adapter les rappels hérités et Combine à async/await
  3. Tester le code asynchrone (XCTest)
← Retour à Swift Academy