0Pricing
Swift Academy · Урок

Производитель и потребитель, конвейеры, тайм-ауты

Создайте простой механизм производитель/потребитель , объединяйте конвейеры с помощью AsyncSequence и реализуйте тайм-аут , состязая задачу сна с основной задачей.

«Производитель и потребитель, конвейеры, тайм-ауты» — бесплатный урок Swift Academy на CoddyKit. Это урок 1 из 3. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Swift Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Swift Academy содержит 3 уроков всего.

Что Вы создадите

В этом уроке рассматриваются три шаблона:

  • Производитель/потребитель с использованием AsyncStream
  • Конвейеры с преобразованиями AsyncSequence
  • Ограничения времени с помощью согласованного соперничества задач

Базовый производитель/потребитель

AsyncStream связывает производителей, работающих по модели передачи данных, с потреблением через 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()
}

Политика противодавления

Выберите bufferingPolicy, чтобы управлять противодавлением: отбрасывать самые старые или самые новые элементы либо использовать неограниченный буфер для небольших потоков.

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

Конвейер с AsyncSequence

AsyncSequence поддерживает знакомые операторы (преобразование, фильтрация, reduce), поэтому Вы можете создавать понятные потоковые конвейеры.

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

Параллельный этап

Используйте группы задач внутри конвейеров для преобразований, ограниченных возможностями CPU, а затем объединяйте результаты в удобном для Вас порядке.

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

Вспомогательная функция ограничения времени

Реализуйте ограничение времени, запустив операцию одновременно с задачей sleep; выполните cancel проигравшей задачи, чтобы не тратить ресурсы.

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

Шаблон ограничения времени (гонка)

Быстрая проверка: как лучше всего добавить ограничение времени?

Итоги

Итоги:

  • Используйте AsyncStream для модели производителя/потребителя.
  • Составляйте конвейеры AsyncSequence с преобразованием, фильтрацией и reduce.
  • Реализуйте ограничения времени, устраивая гонку задач и выполняя cancel проигравшей задачи.

Часто задаваемые вопросы

Урок «Производитель и потребитель, конвейеры, тайм-ауты» бесплатный?

Да — полный текст урока «Производитель и потребитель, конвейеры, тайм-ауты» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Swift Academy, подпишись на CoddyKit PRO. Курс Swift Academy содержит 3 уроков всего.

Чему я научусь в уроке «Производитель и потребитель, конвейеры, тайм-ауты»?

Создайте простой механизм производитель/потребитель , объединяйте конвейеры с помощью AsyncSequence и реализуйте тайм-аут , состязая задачу сна с основной задачей. Ты практикуешь Swift Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Swift Academy?

Предыдущий опыт не требуется. Swift Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 3.

Сколько времени занимает урок «Производитель и потребитель, конвейеры, тайм-ауты»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Swift Academy?

Да. Каждый урок Swift Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Производитель и потребитель, конвейеры, тайм-ауты
  2. Переход от устаревших обратных вызовов и Combine к async/await
  3. Тестирование асинхронного кода (XCTest)
← Назад к Swift Academy