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
Swift Concurrencyとレースコンディション
Search
Yuki Yasoshima
August 25, 2024
Programming
2
700
Swift Concurrencyとレースコンディション
After iOSDC Japan 2024
2024/8/26
Yuki Yasoshima
August 25, 2024
Tweet
Share
More Decks by Yuki Yasoshima
See All by Yuki Yasoshima
Swift Concurrency - 状態監視の罠
objectiveaudio
2
530
モーダルの遷移を理解する
objectiveaudio
4
2.2k
オーディオ波形を表示するために知っておくべきこと
objectiveaudio
0
980
AVAudioEngineでリアルタイムレンダリング
objectiveaudio
1
850
リファクタリング・チャレンジ リバーシ編
objectiveaudio
0
170
UIKitは2度ベルを鳴らす
objectiveaudio
0
310
iOSDC2018.pdf
objectiveaudio
1
2.2k
Objective-C++を使ってMRCで快適に開発する
objectiveaudio
0
23k
Other Decks in Programming
See All in Programming
アメ車でサンノゼを走ってきたよ!
s_shimotori
0
230
CSC305 Lecture 08
javiergs
PRO
0
210
Goで実践するドメイン駆動開発 AIと歩み始めた新規プロダクト開発の現在地
imkaoru
4
850
10年もののAPIサーバーにおけるCI/CDの改善の奮闘
mbook
0
830
Server Side Kotlin Meetup vol.16: 内部動作を理解して ハイパフォーマンスなサーバサイド Kotlin アプリケーションを書こう
ternbusty
3
200
3年ぶりにコードを書いた元CTOが Claude Codeと30分でMVPを作った話
maikokojima
0
370
なぜあの開発者はDevRelに伴走し続けるのか / Why Does That Developer Keep Running Alongside DevRel?
nrslib
3
410
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
400
bootcamp2025_バックエンド研修_WebAPIサーバ作成.pdf
geniee_inc
0
110
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
170
kiroとCodexで最高のSpec駆動開発を!!数時間で web3ネイティブなミニゲームを作ってみたよ!
mashharuki
0
570
AIと人間の共創開発!OSSで試行錯誤した開発スタイル
mae616
1
500
Featured
See All Featured
Fashionably flexible responsive web design (full day workshop)
malarkey
407
66k
Code Review Best Practice
trishagee
72
19k
Navigating Team Friction
lara
190
15k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
16
1.7k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
248
1.3M
How STYLIGHT went responsive
nonsquared
100
5.8k
Scaling GitHub
holman
463
140k
Learning to Love Humans: Emotional Interface Design
aarron
274
41k
RailsConf 2023
tenderlove
30
1.2k
Music & Morning Musume
bryan
46
6.8k
The World Runs on Bad Software
bkeepers
PRO
72
11k
Practical Orchestrator
shlominoach
190
11k
Transcript
:VLJ:BTPTIJNB!ZBTP@TBO 4XJGU$PODVSSFODZͱ ϨʔείϯσΟγϣϯ "GUFSJ04%$+BQBO
ඇಉظॲཧͰى͖Δ w σʔλڝ߹ w ϨʔείϯσΟγϣϯ ؒҧͬͨίʔυΛॻ͍ͯେͳ͘ಈ͍ͯ͠·͏
4XJGU$PODVSSFODZͰʁ w 4XJGU$PODVSSFODZ͕ίϯύΠϧ࣌ʹอূ͢Δͷσʔλڝ߹·Ͱ w ϨʔείϯσΟγϣϯͷɺ ҎલͱมΘΒ࣮ͣऀ͕ؾΛ͚ͭΔඞཁ͕͋Δ
4XJGU$PODVSSFODZͷΈ w "DUPSSFFOUSBODZʢ"DUPSͷ࠶ೖՄೳੑʣ w $PPQFSBUJWF5ISFBE1PPMʢڠௐతεϨουϓʔϧʣ
nonisolated func asyncMethod(_ value: Int) async -> Int { ...
} ... Task { @MainActor in let value = makeValue() let result = await asyncMethod(value) print("result : \(result)") } ॲཧ͕ܧଓ࣮ͯ͠ߦ͞ΕΔ୯Ґ ᶃ ᶄ ᶅ ᶃϝΠϯ ᶄ#( ᶅϝΠϯ 4VTQFOUJPO1PJOU εϨου $POUJOVBUJPO ϝΠϯ
nonisolated func asyncMethod(_ value: Int) async -> Int { ...
} ... Task { @MainActor in let value = makeValue() let result = await asyncMethod(value) print("result : \(result)") } ॲཧ͕ܧଓ࣮ͯ͠ߦ͞ΕΔ୯Ґ ᶃ ᶄ ᶅ ᶃϝΠϯ ᶄ ᶅϝΠϯ 4VTQFOUJPO1PJOU εϨου $POUJOVBUJPO ᶄ ᶄ
$PPQFSBUJWF5ISFBE1PPM ڠௐతεϨουϓʔϧ εϨου εϨου ࣮ߦͪ "DUPSᶃ "DUPSᶄ /PO*TPMBUFE Task {
@MainActor in let value = makeValue() let result = await asyncMethod(value) return "fetched : " + result } Task { } 5BTLͷ࣮ߦ
nonisolated func method() { ᶃ Task.detached { ᶄ } Task.detached
{ ᶅ } ᶆ } ࣮ߦ͞ΕΔॱ൪ w ᶄɺᶅɺᶆฒྻͰ࣮ߦ͞ ΕΔ શͯ/PO*TPMBUFEͷ߹ ᶃ ᶆ ᶄ ᶅ εϨου
nonisolated func method() { ᶃ Task.detached { ᶄ } Task.detached
{ ᶅ } ᶆ } ࣮ߦ͞ΕΔॱ൪ w ᶄɺᶅɺᶆฒྻͰ࣮ߦ͞ ΕΔ w ᶆͷޙʹᶄɺᶅ͕ಉ͡εϨ ουͷՄೳੑͳ͘ͳ͍ શͯ/PO*TPMBUFEͷ߹ ᶃ ᶆ ᶄ ᶅ εϨου ᶄ ᶅ
@MyActor func method() { ᶃ Task { @MyActor in ᶄ
} Task { @MyActor in ᶅ } ᶆ } w ·ͣᶃɺᶆ͕࣮ߦ͞ΕΔ w ᶄɺᶅ ฒྻʹ࣮ߦ͞Εͳ͍͕ ͲͪΒ͔Β ࣮ߦ͞ΕΔ͔Θ͔Βͳ͍ ࣮ߦ͞ΕΔॱ൪ ಉ͡"DUPSͷ߹ εϨου ᶃ ᶆ ᶄ ᶅ ᶄ ᶅ ʁ
ͷ͋ΔίʔυΛվળ͢Δ
ͷ͋Δίʔυྫ λοϓͨ͠ͷϩάΛૹΔ w λοϓ͢ΔͨͼʹϩʔΧϧʹอ͍࣋ͯ͠ΔΛ૿͢ w ఆظతʹΛαʔόʔʹૹ৴͢Δ w ૹ৴ͨ͠ΒϩʔΧϧͷΛϦηοτ͢Δ
ͷ͋Δίʔυྫ 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() } }
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͞ΕΔ
class CountLogger { func increment() async { ... } ...
func post() async { let count = await counter.count await counter.reset() await postCountLog(count) } } w DPVOUऔಘޙʹ͙͢SFTFUͯ͠ɺ 4VTQFOUJPO1PJOUͰJODSFNFOU͕ݺΕΔՄೳੑ͕͋Δ
actor CountLogger { func increment() async { ... } ...
func post() async { let count = await counter.count await counter.reset() await postCountLog(count) } } w BDUPSʹͯ͠4VTQFOUJPO1PJOU͕ೖΔ͜ͱมΘΒͳ͍
վળͨ͠ίʔυ 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) } }
actor Counter { private var count: Int = 0 ...
func pull() -> Int { let count = self.count self.count = 0 return count } } w DPVOUͷऔಘͱϦηοτΛBDUPSͷϝιουͭͰߦ͏͜ͱͰ 4VTQFOUJPO1PJOU͕ೖΔ͜ͱͳ͘ͳΔ
αϯϓϧͷ༷มߋ λοϓͨ͠ͷϩάΛૹΓ߹ܭΛදࣔ w λοϓ͢ΔͨͼʹϩʔΧϧʹอ͍࣋ͯ͠ΔΛ૿͢ w ఆظతʹΛαʔόʔʹૹ৴͢Δ w ૹ৴ͨ͠ΒϩʔΧϧͷΛϦηοτ͢Δ w ૹ৴࣌ʹαʔόʔ͔Β߹ܭΛฦ͠දࣔ͢Δ
/FX
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 } ઌʹݺΜͩॲཧ ޙ͔ΒݺΜͩॲཧ
w ݺͼग़͢λΠϛϯά͕ॏෳ͢Δͱ͕ى͖ΔՄೳੑ͕͋Δ Task { let total = await logger.post() print("total
: \(total)") } ͱΓ͋͑ͣ5BTL ❓
5JNFSͰ5BTLΛ܁Γฦ࣮͠ߦ w QPTUͷॲཧ͕5JNFSͷJOUFSWBMΛ͑Δͱɺ QPTUͷॲཧ͕ॏෳ͢ΔՄೳੑ͕͋Δ Timer.scheduledTimer(withTimeInterval: 10, repeats: true) { _
in Task { let total = await logger.post() print("total : \(total)") } } ❌
w 5BTLͷதͰϧʔϓ͢ΕɺQPTUͷॲཧॏෳ͠ͳ͍ Task { while true { await logger.post() print("total
: \(total)") try await Task.sleep(for: .seconds(10)) } } 5BTLͰ܁Γฦ࣮͠ߦ
αϯϓϧͷ༷มߋ λοϓͨ͠ͷϩάΛૹΓ߹ܭΛදࣔ w λοϓ͢ΔͨͼʹϩʔΧϧʹอ͍࣋ͯ͠ΔΛ૿͢ w ఆظతʹΛαʔόʔʹૹ৴͢Δ w ૹ৴ͨ͠ΒϩʔΧϧͷΛϦηοτ͢Δ w ૹ৴࣌ʹαʔόʔ͔Β߹ܭΛฦ͠දࣔ͢Δ
w ࣗ༝ͳλΠϛϯάͰΛαʔόʔʹૹ৴͢Δ /FX
var isProcessing: Bool = false func post() { Task {
guard !isProcessing else { return } isProcessing = true let total = await logger.post() print("total : \(total)”) isProcessing = false } } ˞"DUPSಉ͡ఆ ඇಉظॲཧͷॏෳΛεΩοϓ
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Λ͏
·ͱΊ 4XJGU$PODVSSFODZͱϨʔείϯσΟγϣϯ w 4XJGU$PODVSSFOUZϨʔείϯσΟγϣϯΛ͍Ͱ͘ΕΔͷͰͳ͍ w Ή͠ΖޮΛ༏ઌͯ͠Λى͍͜͢͠Έʹͳ͍ͬͯΔ w "DUPSSFFOUSBODZ w ಉ͡BDUPSಉ࢜ͷॲཧͰɺBXBJUͰڬΈࠐ·ΕΔՄೳੑ͕͋Δ
w $PPQFSBUJWF5ISFBE1PPM w εϨουͰ࣮ߦ͞ΕΔॱ൪ɺ࣮ߦ։࢝͠Α͏ͱͨ͠ॱ൪ͱݶΒͳ͍
·ͱΊ ϨʔείϯσΟγϣϯͷରԠ w ہॴతʹҰͭͷBDUPSͷதͰBTZODؔΛΘͣʹ Ͳ͏ݺΕͯෆ߹͕ى͖ͳ͍ঢ়ଶΛ࡞Δ w BTZODؔΛΈ߹Θͤͳ͍ͱ͍͚ͳ͚Εɺ ΫϦςΟΧϧηΫγϣϯ͕ಉ࣌ʹ࣮ߦ͞Εͳ͍Α͏ʹߟྀ࣮ͯ͢͠Δ
ࢀߟ w 88%$ w .FFUBTZODBXBJUJO4XJGU w 1SPUFDUNVUBCMFTUBUFXJUI4XJGUBDUPST w 4XJGUDPODVSSFODZ#FIJOEUIFTDFOFT