Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
AsyncStreamでマルチブロードキャストを実装する
Search
1mash0
May 20, 2026
Technology
270
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
AsyncStreamでマルチブロードキャストを実装する
DMM.swift #5
1mash0
May 20, 2026
More Decks by 1mash0
See All by 1mash0
What's new in SwiftData + SwiftData Group Lab Recap
1mash0
0
46
SwiftData: Dive into inheritance and schema migration - Swift愛好会スピンオフ WWDC25セッション要約会
1mash0
0
480
SwiftDataのカスタムデータストアを試してみた
1mash0
0
360
Other Decks in Technology
See All in Technology
最新技術に積極チャレンジ!EKS共通基盤のこれまでとこれから
daitak
0
290
Continuous Delivery! It is not what you think it is
tdpauw
0
180
【5分でわかる】セーフィー エンジニア向け会社紹介
safie_recruit
0
55k
Bet AI Day 2026丨Production-Ready AI Agents — エンタープライズの実務を任せるための設計と運用
layerx
PRO
2
1.7k
PM領域でのAI Agentの活用
lycorptech_jp
PRO
0
230
Driving AI Adoption Using In-House GPUs to Serve Qwen
po3rin
2
350
分割40%キーボードにスムーズに入門するには
hoto17296
1
220
AIエージェントの開発・提供におけるセキュリティリスクの論点と対策
flatt_security
1
370
魔法少女がClaude Codeを監視する / ccportal-deck
noriyukitakei
3
120
いま、生成AIにKaggleをどこまで 任せられるか — ROGIIコンペでの進め方とTips
k951286
1
1.2k
DINO-EdgeQuery:Edge-First Polygon Decoding for Building Footprint Extraction from Satellite Imagery
lehupa
0
130
Bet AI Day 2026丨AIを「使う」から、AIが「働く」へ ― LayerXが進める「組織AI」の社会実装
layerx
PRO
2
1.5k
Featured
See All Featured
The AI Revolution Will Not Be Monopolized: How open-source beats economies of scale, even for LLMs
inesmontani
PRO
3
3.7k
State of Search Keynote: SEO is Dead Long Live SEO
ryanjones
0
260
From Legacy to Launchpad: Building Startup-Ready Communities
dugsong
0
320
Why Our Code Smells
bkeepers
PRO
340
58k
Navigating Weather and Climate Data
rabernat
0
500
Lightning talk: Run Django tests with GitHub Actions
sabderemane
0
250
Technical Leadership for Architectural Decision Making
baasie
3
550
Java REST API Framework Comparison - PWX 2021
mraible
34
9.7k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
10k
How to Get Subject Matter Experts Bought In and Actively Contributing to SEO & PR Initiatives.
livdayseo
0
180
Un-Boring Meetings
codingconduct
0
400
Context Engineering - Making Every Token Count
addyosmani
9
1.1k
Transcript
͍·͑͢ "TZOD4USFBNͰϚϧνϒϩʔυ ΩϟετΛ࣮͢Δ %..TXJGU !NBTO@
"TZOD4USFBN w "TZOD4USFBN"TZOD4FRVFODFʹ४ڌ w ඇಉظΠςϨʔλΛखಈͰ࣮͢Δ͜ͱͳ͘ඇಉظγʔέϯεΛ࡞Ͱ͖Δ w DBMMCBDLEFMFHBUFϕʔεͷ"1*ΛBTZODBXBJUʹରԠͤ͞Δͷʹదͯ͠Δ w "TZOD4USFBN$POUJOVBUJPOΛड͚औΔΫϩʔδϟΛ༻ͯ͠ॳظԽ͢Δ w
$POUJOVBUJPOZJFME @ ϝιουΛݺͼग़ͯ͠ཁૉΛετϦʔϜʹ͢ w $POUJOVBUJPO fi OJTI Ͱऴྃ͢Δ
let stream = AsyncStream<Int> { continuation in Task { var
count = 1 while !Task.isCancelled { continuation.yield(count) count += 1 try? await Task.sleep(for: .seconds(1)) } } } let taskA = Task { for await value in stream { print("Task A:", value) } } let taskB = Task { for await value in stream { print("Task B:", value) } } try? await Task.sleep(for: .seconds(3)) taskA.cancel() try? await Task.sleep(for: .seconds(3))
"TZOD4USFBNϒϩʔυΩϟετͰͳ͍ w ྫ͑$PNCJOFͷ1BTTUISPVHI4VCKFDUʮϒϩʔυΩϟετ͢Δʯͱઆ໌ ͞Ε͍ͯΔ ʮA subject that broadcasts elements to
downstream subscribers.ʯ w Ұํ"TZOD4USFBN"TZOD4FRVFODFΛ࡞͢Δܕͱͯ͠આ໌͞Ε͍ͯΔ ʮAn asynchronous sequence generated from a closure that calls a continuation to produce new elements.ʯ
4&
"TZOD4USFBNͰϚϧνϒϩʔυΩϟετͷ࣮ํ๏ w ߪಡऀ͝ͱʹ"TZOD4USFBNΛੜ͢Δ w ߪಡऀ͝ͱͷ$POUJOVBUJPOΛ66*%Ͱཧ͢Δ w PO5FSNJOBUJPOͰऴྃͨ͠$POUJOVBUJPOΛআ͢Δ w ݩͷΠϕϯτιʔε͚ͭͩʹ͢Δ w
શ$POUJOVBUJPOZJFME @ ͢Δ
"TZOD4USFBNͰϚϧνϒϩʔυΩϟετͷ࣮ํ๏ w ߪಡऀ͝ͱʹ"TZOD4USFBNΛੜ͢Δ w ߪಡऀ͝ͱͷ$POUJOVBUJPOΛ66*%Ͱཧ͢Δ w PO5FSNJOBUJPOͰऴྃͨ͠$POUJOVBUJPOΛআ͢Δ w ݩͷΠϕϯτιʔε͚ͭͩʹ͢Δ w
શ$POUJOVBUJPOZJFME @ ͢Δ
private var continuations: [UUID: AsyncStream<Int>.Continuation] = [:] func stream() ->
AsyncStream<Int> { let id = UUID() let (stream, continuation) = AsyncStream<Int>.makeStream( of: Int.self, bufferingPolicy: self.bufferingPolicy ) continuations[id] = continuation continuation.onTermination = { [weak self] _ in Task { await self?.removeContinuation(id) } } return stream }
4&
"TZOD4USFBNͰϚϧνϒϩʔυΩϟετͷ࣮ํ๏ w ߪಡऀ͝ͱʹ"TZOD4USFBNΛੜ͢Δ w ߪಡऀ͝ͱͷ$POUJOVBUJPOΛ66*%Ͱཧ͢Δ w PO5FSNJOBUJPOͰऴྃͨ͠$POUJOVBUJPOΛআ͢Δ w ݩͷΠϕϯτιʔε͚ͭͩʹ͢Δ w
શ$POUJOVBUJPOZJFME @ ͢Δ
continuation.onTermination = { [weak self] _ in Task { await
self?.removeContinuation(id) } } private func removeContinuation(_ id: UUID) { continuations[id] = nil }
"TZOD4USFBNͰϚϧνϒϩʔυΩϟετͷ࣮ํ๏ w ߪಡऀ͝ͱʹ"TZOD4USFBNΛੜ͢Δ w ߪಡऀ͝ͱͷ$POUJOVBUJPOΛ66*%Ͱཧ͢Δ w PO5FSNJOBUJPOͰऴྃͨ͠$POUJOVBUJPOΛআ͢Δ w ݩͷΠϕϯτιʔε͚ͭͩʹ͢Δ w
શ$POUJOVBUJPOZJFME @ ͢Δ
private var task: Task<Void, Never>? func start() { task?.cancel() task
= Task { [weak self] in var count = 1 while !Task.isCancelled { await self?.yield(count) count += 1 try? await Task.sleep(for: .seconds(1)) } } }
"TZOD4USFBNͰϚϧνϒϩʔυΩϟετͷ࣮ํ๏ w ߪಡऀ͝ͱʹ"TZOD4USFBNΛੜ͢Δ w ߪಡऀ͝ͱͷ$POUJOVBUJPOΛ66*%Ͱཧ͢Δ w PO5FSNJOBUJPOͰऴྃͨ͠$POUJOVBUJPOΛআ͢Δ w ݩͷΠϕϯτιʔε͚ͭͩʹ͢Δ w
શ$POUJOVBUJPOZJFME @ ͢Δ
func yield(_ value: Int) { for continuation in continuations.values {
continuation.yield(value) } } func finish() { task?.cancel() task = nil for continuation in continuations.values { continuation.finish() } continuations.removeAll() }
actor Broadcast { typealias BufferingPolicy = AsyncStream<Int>.Continuation .BufferingPolicy private var
continuations: [UUID: AsyncStream<Int>.Continuation] = [:] private let bufferingPolicy: BufferingPolicy private var task: Task<Void, Never>? init(bufferingPolicy: BufferingPolicy) { self.bufferingPolicy = bufferingPolicy } func stream() -> AsyncStream<Int> { let id = UUID() let (stream, continuation) = AsyncStream<Int>.makeStream( of: Int.self, bufferingPolicy: self.bufferingPolicy ) continuations[id] = continuation continuation.onTermination = { [weak self] _ in Task { await self?.removeContinuation(id) } } return stream } func start() { task?.cancel() task = Task { [weak self] in var count = 1 while !Task.isCancelled { await self?.yield(count) count += 1 try? await Task.sleep(for: .seconds(1)) } } } func yield(_ value: Int) { for continuation in continuations.values { continuation.yield(value) } } func finish() { task?.cancel() task = nil for continuation in continuations.values { continuation.finish() } continuations.removeAll() } private func removeContinuation(_ id: UUID) { continuations[id] = nil } }
let broadcast = Broadcast(bufferingPolicy: .bufferingNewest(1)) let stream1 = await broadcast.stream()
let stream2 = await broadcast.stream() let taskA = Task { for await value in stream1 { print("Task A:", value) } } let taskB = Task { for await value in stream2 { print("Task B:", value) } } await broadcast.start() try? await Task.sleep(for: .seconds(3)) taskA.cancel() try? await Task.sleep(for: .seconds(3))
·ͱΊ w ߪಡऀ͝ͱʹ"TZOD4USFBNΛੜ͢Δ w ߪಡऀ͝ͱͷ"TZOD4USFBN$POUJOVBUJPOΛཧΛ͢Δ w J04ະຬͳΒ66*%Ͱཧ w J04Ҏ্ͳΒ4FUͰཧ w
ݩͷΠϕϯτιʔε͕ॏෳ͠ͳ͍Α͏ʹҙ
TXJGUBTZODBMHPSJUINT w όʔδϣϯ ͔Β4IBSFػೳ͕ಋೖ͞ΕͯϚϧνϒϩʔυΩϟ ετʹରԠͨ͠ w ߪಡͯ͠Δ5BTLΛΩϟϯηϧͯ͠ɺͷ"TZOD4USFBNʹΩϟϯηϧ͕ ͠ͳ͍ͨΊҙ w
ߪಡͯ͠Δ5BTL͕ͬͯΔͱDPOUJOVBUJPOPO5FSNJOBUJPOʹྲྀΕͯ͜ͳ͍
import AsyncAlgorithms let stream = AsyncStream<Int> { continuation in Task
{ var count = 1 while !Task.isCancelled { continuation.yield(count) count += 1 try? await Task.sleep(for: .seconds(1)) } } }.share() let taskA = Task { for await value in stream { print("Task A:", value) } } let taskB = Task { for await value in stream { print("Task B:", value) } } try? await Task.sleep(for: .seconds(3)) taskA.cancel() try? await Task.sleep(for: .seconds(3))
·ͱΊ w ߪಡऀ͝ͱʹ"TZOD4USFBNΛੜ͢Δ w ߪಡऀ͝ͱͷ"TZOD4USFBN$POUJOVBUJPOΛཧΛ͢Δ w J04ະຬͳΒ66*%Ͱཧ w J04Ҏ্ͳΒ4FUͰཧ w
ݩͷΠϕϯτιʔε͕ॏෳ͠ͳ͍Α͏ʹҙ w TXJGUBTZODBMHPSJUINTΛ͓͏