Upgrade to Pro — share decks privately, control downloads, hide ads and more …

AsyncStreamでマルチブロードキャストを実装する

 AsyncStreamでマルチブロードキャストを実装する

DMM.swift #5

Avatar for 1mash0

1mash0

May 20, 2026

More Decks by 1mash0

Other Decks in Technology

Transcript

  1. 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)) 
  2. 

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

  6. continuation.onTermination = { [weak self] _ in Task { await

    self?.removeContinuation(id) } } private func removeContinuation(_ id: UUID) { continuations[id] = nil } 
  7. 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)) } } } 
  8. 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() } 
  9. 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 } } 
  10. 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)) 
  11. 

  12. 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)) 
  13.