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
- Producent/konsument, potoki i limity czasu
- Łączenie starszych callbacków i Combine z async/await
- Testowanie kodu asynchronicznego (XCTest)