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
40
SwiftData: Dive into inheritance and schema migration - Swift愛好会スピンオフ WWDC25セッション要約会
1mash0
0
480
SwiftDataのカスタムデータストアを試してみた
1mash0
0
350
Other Decks in Technology
See All in Technology
Sansan Engineering Unit 紹介資料
sansan33
PRO
1
4.9k
つくって納得、つかって実感! 大規模言語モデルことはじめ ver2.0
recruitengineers
PRO
4
1.6k
Software Supply Chain Attackからクラウド環境を守るためにできること
lhazy
2
260
Sets in Go
ramalho
1
400
Bits Agent Builder の⼊⾨と活⽤事例
nulabinc
PRO
0
140
Flutterをカメラで動かしたかった話
sony
1
140
QAエンジニア起点で進める、SmartHRにおける信頼性向上について
kaomi_wombat
1
140
FPGAが実現する遠方宇宙の高空間分解能天体撮影 -大型地上望遠鏡の視力を補正する「補償光学」とは?-
komei_mt
0
240
モバイルアプリ開発概論2026
recruitengineers
PRO
5
580
モノリス Rails でも日中に rails db:migrate を走らせたい! / Daytime rails db:migrate on Monolithic Rails!
euglena1215
4
580
Breaking the Seal: Static Deobfuscation of Compiled V8 JavaScript Bytecode Malware
hshrzd
0
740
MIRU 2026 チュートリアル
keisuke198619
0
910
Featured
See All Featured
Future Trends and Review - Lecture 12 - Web Technologies (1019888BNR)
signer
PRO
0
3.7k
The Straight Up "How To Draw Better" Workshop
denniskardys
239
140k
The World Runs on Bad Software
bkeepers
PRO
72
12k
Learning to Love Humans: Emotional Interface Design
aarron
275
41k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
35
2.5k
Odyssey Design
rkendrick25
PRO
2
750
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
659
62k
Evolving SEO for Evolving Search Engines
ryanjones
0
250
From Legacy to Launchpad: Building Startup-Ready Communities
dugsong
0
300
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
68
56k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
201
75k
Tell your own story through comics
letsgokoyo
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Λ͓͏