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

Swift Concurrencyとレースコンディション

Swift Concurrencyとレースコンディション

After iOSDC Japan 2024
2024/8/26

Yuki Yasoshima

August 25, 2024
Tweet

More Decks by Yuki Yasoshima

Other Decks in Programming

Transcript

  1. nonisolated func asyncMethod(_ value: Int) async -> Int { ...

    } ... Task { @MainActor in let value = makeValue() let result = await asyncMethod(value) print("result : \(result)") } ॲཧ͕ܧଓ࣮ͯ͠ߦ͞ΕΔ୯Ґ ᶃ ᶄ ᶅ ᶃϝΠϯ ᶄ#( ᶅϝΠϯ 4VTQFOUJPO1PJOU εϨου $POUJOVBUJPO ϝΠϯ
  2. nonisolated func asyncMethod(_ value: Int) async -> Int { ...

    } ... Task { @MainActor in let value = makeValue() let result = await asyncMethod(value) print("result : \(result)") } ॲཧ͕ܧଓ࣮ͯ͠ߦ͞ΕΔ୯Ґ ᶃ ᶄ ᶅ ᶃϝΠϯ ᶄ ᶅϝΠϯ 4VTQFOUJPO1PJOU εϨου $POUJOVBUJPO ᶄ ᶄ
  3. $PPQFSBUJWF5ISFBE1PPM ڠௐతεϨουϓʔϧ εϨου εϨου ࣮ߦ଴ͪ "DUPSᶃ "DUPSᶄ /PO*TPMBUFE Task {

    @MainActor in let value = makeValue() let result = await asyncMethod(value) return "fetched : " + result } Task { } 5BTLͷ࣮ߦ
  4. nonisolated func method() { ᶃ Task.detached { ᶄ } Task.detached

    { ᶅ } ᶆ } ࣮ߦ͞ΕΔॱ൪ w ᶄɺᶅɺᶆ͸ฒྻͰ࣮ߦ͞ ΕΔ શͯ/PO*TPMBUFEͷ৔߹ ᶃ ᶆ ᶄ ᶅ εϨου
  5. nonisolated func method() { ᶃ Task.detached { ᶄ } Task.detached

    { ᶅ } ᶆ } ࣮ߦ͞ΕΔॱ൪ w ᶄɺᶅɺᶆ͸ฒྻͰ࣮ߦ͞ ΕΔ w ᶆͷޙʹᶄɺᶅ͕ಉ͡εϨ ουͷՄೳੑ΋ͳ͘͸ͳ͍ શͯ/PO*TPMBUFEͷ৔߹ ᶃ ᶆ ᶄ ᶅ εϨου ᶄ ᶅ
  6. @MyActor func method() { ᶃ Task { @MyActor in ᶄ

    } Task { @MyActor in ᶅ } ᶆ } w ·ͣᶃɺᶆ͕࣮ߦ͞ΕΔ w ᶄɺᶅ͸ ฒྻʹ͸࣮ߦ͞Εͳ͍͕ ͲͪΒ͔Β ࣮ߦ͞ΕΔ͔͸Θ͔Βͳ͍ ࣮ߦ͞ΕΔॱ൪ ಉ͡"DUPSͷ৔߹ εϨου ᶃ ᶆ ᶄ ᶅ ᶄ ᶅ ʁ
  7. ໰୊ͷ͋Δίʔυྫ actor Counter { var count: Int = 0 func

    increment() { count += 1 } func reset() { count = 0 } } class CountLogger { private let counter = Counter() func increment() async { await counter.increment() } // ఆظతʹؒΛ͓͍ͯݺ͹ΕΔ૝ఆ func post() async { let count = await counter.count await postCountLog(count) await counter.reset() } }
  8. class CountLogger { func increment() async { ... } ...

    func post() async { let count = await counter.count await postCountLog(count) await counter.reset() } } w DPVOUऔಘ͔ͯ͠ΒSFTFU͢Δ·ͰͷؒʹJODSFNFOU ͕ݺ͹ΕΔͱ ͦͷ૿Ճ෼͸QPTU͞ΕͣʹSFTFU͞ΕΔ
  9. class CountLogger { func increment() async { ... } ...

    func post() async { let count = await counter.count await counter.reset() await postCountLog(count) } } w DPVOUऔಘޙʹ͙͢SFTFUͯ͠΋ɺ 4VTQFOUJPO1PJOUͰJODSFNFOU͕ݺ͹ΕΔՄೳੑ͕͋Δ
  10. actor CountLogger { func increment() async { ... } ...

    func post() async { let count = await counter.count await counter.reset() await postCountLog(count) } } w BDUPSʹͯ͠΋4VTQFOUJPO1PJOU͕ೖΔ͜ͱ͸มΘΒͳ͍
  11. վળͨ͠ίʔυ actor Counter { private var count: Int = 0

    func increment() { count += 1 } func pull() -> Int { let count = self.count self.count = 0 return count } } actor CountLogger { private let counter = Counter() func increment() async { await counter.increment() } // ఆظతʹؒΛ͓͍ͯݺ͹ΕΔ૝ఆ func post() async { let count = await counter.pull() await postCountLog(count) } }
  12. actor Counter { private var count: Int = 0 ...

    func pull() -> Int { let count = self.count self.count = 0 return count } } w DPVOUͷऔಘͱϦηοτΛBDUPSͷϝιουͭͰߦ͏͜ͱͰ 4VTQFOUJPO1PJOU͕ೖΔ͜ͱͳ͘ͳΔ
  13. func post() async -> Int { let count = await

    counter.pull() let total = await postCountLog(count) return total } w ಉ࣌ʹݺ͹ΕΔͱɺޙ͔ΒݺΜͩํ͕ઌʹऴΘΔՄೳੑ͕͋Δ w BDUPS͕ಉ͡Ͱ΋ؔ܎ͳ͍ func post() async -> Int { let count = await counter.pull() let total = await postCountLog(count) return total } ઌʹݺΜͩॲཧ ޙ͔ΒݺΜͩॲཧ
  14. w 5BTLͷதͰϧʔϓ͢Ε͹ɺQPTUͷॲཧ͸ॏෳ͠ͳ͍ Task { while true { await logger.post() print("total

    : \(total)") try await Task.sleep(for: .seconds(10)) } } 5BTLͰ܁Γฦ࣮͠ߦ
  15. var isProcessing: Bool = false func post() { Task {

    guard !isProcessing else { return } isProcessing = true let total = await logger.post() print("total : \(total)”) isProcessing = false } } ˞"DUPS͸ಉ͡૝ఆ ඇಉظॲཧͷॏෳΛεΩοϓ
  16. w ௚઀࣮ߦͤͣɺผ5BTLͰඇಉظॲཧ͕௚ྻʹ࣮ߦ͞ΕΔΑ͏ʹ͢Δ w ͨͩ͠ɺݺͼग़͠ଆ͕࣮ࡍͷඇಉظॲཧͷ׬ྃΛ଴ͭ͜ͱ͸Ͱ͖ͳ͍ let channel: AsyncChannel<Void> Task { for

    await _ in channel { let total = await logger.post() print("total : \(total)") } } Task { await channel.send(()) } "TZOD$IBOOFMΛ࢖͏