プロデューサー/コンシューマー、パイプライン、タイムアウト
シンプルな プロデューサー/コンシューマー を構築し、AsyncSequenceで パイプライン を組み合わせます。また、sleepタスクとの競争によって タイムアウト を実装します。
「プロデューサー/コンシューマー、パイプライン、タイムアウト」はCoddyKit上の無料Swift Academyレッスンです。 これはレッスン1/3です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはSwift Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Swift Academyコースには全3レッスンが含まれています。
このレッスンで作るもの
このレッスンでは、次の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は、おなじみの演算子(map、filter、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タスクと競合させて実装します。処理を節約するため、負けた方をキャンセルしてください。
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を使います。
- map/filter/reduceでAsyncSequenceのパイプラインを組み合わせます。
- タスクを競合させ、負けた方をキャンセルしてタイムアウトを実装します。
AI チューターと学ぶ Swift — 無料
ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。
- コース
- 122
- レッスン
- 409
よくある質問
「プロデューサー/コンシューマー、パイプライン、タイムアウト」レッスンは無料ですか?
はい。「プロデューサー/コンシューマー、パイプライン、タイムアウト」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Swift Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Swift Academyコースには全3レッスンが含まれています。
「プロデューサー/コンシューマー、パイプライン、タイムアウト」で何を学びますか?
シンプルな プロデューサー/コンシューマー を構築し、AsyncSequenceで パイプライン を組み合わせます。また、sleepタスクとの競争によって タイムアウト を実装します。 ブラウザで直接実行するハンズオンコードでSwift Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Swift Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのSwift Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/3です。
「プロデューサー/コンシューマー、パイプライン、タイムアウト」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このSwift Academyレッスンでコードを書いて実行できますか?
はい。すべてのSwift Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- プロデューサー/コンシューマー、パイプライン、タイムアウト
- 従来のコールバック/Combineとasync/awaitの橋渡し
- 非同期コードのテスト(XCTest)