Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
AsyncStreamでマルチブロードキャストを実装する
Search
1mash0
May 20, 2026
Technology
290
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
Minecraft JavaのMODをSwiftで作る
1mash0
0
200
What's new in SwiftData + SwiftData Group Lab Recap
1mash0
0
57
SwiftData: Dive into inheritance and schema migration - Swift愛好会スピンオフ WWDC25セッション要約会
1mash0
0
490
SwiftDataのカスタムデータストアを試してみた
1mash0
0
360
Other Decks in Technology
See All in Technology
白金鉱業Meetup Vol.25 アウトカムが二値のデータに対するCausal Impact
brainpadpr
0
290
ほんとうの信頼性はヒーローが死んでからはじまる / True reliability begins after the hero dies
vtryo
0
120
地方移住と都心キャリアの両立は「金・時間・人」のリソースをフル活用すれば実現できる!〜Snowflake女子会 vol.8
snowwmn0824
0
110
AIエージェントの権限管理 3: Agentic RAG の Fine grained access control 編
ren8k
0
240
2026-09-08 そのJavaモダナイゼーション、AIに丸投げで大丈夫?IBM Bobで変わる品質と効率
yutanonaka
1
170
「今盗んで、後で解く」に備える ― AWSのポスト量子暗号入門
yama3133
1
190
AI時代、データエンジニアが一番おもろい
genshun9
0
690
beyond jj: config & tools ecosystem
indirect
0
5.9k
Deployment の 先にある AI Agent 基盤 - kagent vNext、Agent Substrate、Hermes から読み解く Agent Runtime の現在地 / k8s-matsuri-2-ai-agent-platform-amsy810
masayaaoyama
5
720
データ_AIの事業の勝敗をわけるもの
nek0128
1
480
AIに書かせて、プラットフォームで縛る ― EKSプラットフォームで実践した責任境界と権限設計
elmodev09
0
130
AWS DevOps Agent スキルをつかいこなそう / Master AWS DevOps Agent Skills
kinunori
1
220
Featured
See All Featured
YesSQL, Process and Tooling at Scale
rocio
174
15k
How to Get Subject Matter Experts Bought In and Actively Contributing to SEO & PR Initiatives.
livdayseo
0
200
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
230
23k
Mobile First: as difficult as doing things right
swwweet
225
10k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
128
56k
Fireside Chat
paigeccino
43
4k
Exploring the relationship between traditional SERPs and Gen AI search
raygrieselhuber
PRO
3
4.3k
The State of eCommerce SEO: How to Win in Today's Products SERPs - #SEOweek
aleyda
2
12k
The Curious Case for Waylosing
cassininazir
1
530
RailsConf 2023
tenderlove
30
1.6k
Learning to Love Humans: Emotional Interface Design
aarron
275
41k
Build The Right Thing And Hit Your Dates
maggiecrowley
39
3.5k
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Λ͓͏