0Pricing
Swift Academy · Lekcja

Producent/konsument, potoki i limity czasu

Zbuduj prosty mechanizm producent/konsument , twórz potoki za pomocą AsyncSequence i zaimplementuj limit czasu , wyścigując zadanie uśpienia z właściwą pracą.

Producent/konsument, potoki i limity czasu to bezpłatna lekcja Swift Academy na CoddyKit. To lekcja 1 z 3. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Swift Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Swift Academy zawiera 3 lekcji w sumie.

Co zostanie zbudowane

W tej lekcji przedstawiono trzy wzorce:

  • Producent/konsument z użyciem AsyncStream
  • Potoki wykorzystujące transformacje AsyncSequence
  • Limity czasu realizowane przez kooperacyjny wyścig zadań

Podstawowy wzorzec producent/konsument

AsyncStream łączy producentów działających w modelu push z konsumpcją opartą na pobieraniu (pull), realizowaną przez 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()
}

Zasady obsługi backpressure

Należy wybrać bufferingPolicy, aby zarządzać mechanizmem backpressure (odrzucać najstarsze elementy, odrzucać najnowsze lub używać nieograniczonego bufora w przypadku małych strumieni).

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

Potok z AsyncSequence

AsyncSequence udostępnia typowe operatory (map, filter, reduce), dzięki czemu można przejrzyście budować potoki strumieniowe.

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

Etap równoległy

W potokach należy używać grup zadań do transformacji obciążających procesor, a następnie scalać wyniki w wybranej kolejności.

// 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"]
}

Funkcja pomocnicza limitu czasu

Limit czasu można zaimplementować, uruchamiając operację w wyścigu z zadaniem sleep; przegrane zadanie należy anulować, aby oszczędzić zasoby.

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

Wzorzec limitu czasu (wyścig)

Szybkie sprawdzenie: Jaki jest dobry sposób na dodanie limitu czasu?

Podsumowanie

Podsumowanie:

  • Należy używać AsyncStream w modelu producent/konsument.
  • Należy komponować potoki AsyncSequence za pomocą map/filter/reduce.
  • Należy implementować limity czasu, uruchamiając zadania w wyścigu i anulując przegrane.

Często zadawane pytania

Czy lekcja „Producent/konsument, potoki i limity czasu” jest bezpłatna?

Tak — pełny tekst „Producent/konsument, potoki i limity czasu” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Swift Academy, przejdź na CoddyKit PRO. Kurs Swift Academy zawiera 3 lekcji w sumie.

Co nauczysz się w „Producent/konsument, potoki i limity czasu”?

Zbuduj prosty mechanizm producent/konsument , twórz potoki za pomocą AsyncSequence i zaimplementuj limit czasu , wyścigując zadanie uśpienia z właściwą pracą. Ćwiczysz Swift Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Swift Academy?

Nie wymagamy żadnego doświadczenia. Swift Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 1 z 3.

Ile czasu zajmuje lekcja „Producent/konsument, potoki i limity czasu”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Swift Academy?

Tak. Każda lekcja Swift Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Producent/konsument, potoki i limity czasu
  2. Łączenie starszych callbacków i Combine z async/await
  3. Testowanie kodu asynchronicznego (XCTest)
← Powrót do Swift Academy