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
1
550
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
モーダルの遷移を理解する
objectiveaudio
4
1.8k
オーディオ波形を表示するために知っておくべきこと
objectiveaudio
0
870
AVAudioEngineでリアルタイムレンダリング
objectiveaudio
1
730
リファクタリング・チャレンジ リバーシ編
objectiveaudio
0
140
UIKitは2度ベルを鳴らす
objectiveaudio
0
290
iOSDC2018.pdf
objectiveaudio
1
2k
Objective-C++を使ってMRCで快適に開発する
objectiveaudio
0
22k
Other Decks in Programming
See All in Programming
快速入門可觀測性
blueswen
0
500
CQRS+ES の力を使って効果を感じる / Feel the effects of using the power of CQRS+ES
seike460
PRO
0
240
Simple組み合わせ村から大都会Railsにやってきた俺は / Coming to Rails from the Simple
moznion
3
2.2k
知られざるDMMデータエンジニアの生態 〜かつてツチノコと呼ばれし者〜
takaha4k
1
450
PSR-15 はあなたのための ものではない? - phpcon2024
myamagishi
0
410
DevFest - Serverless 101 with Google Cloud Functions
tunmise
0
140
Lookerは可視化だけじゃない。UIコンポーネントもあるんだ!
ymd65536
1
130
KMP와 kotlinx.rpc로 서버와 클라이언트 동기화
kwakeuijin
0
300
ChatGPT とつくる PHP で OS 実装
memory1994
PRO
3
190
DevinとCursorから学ぶAIエージェントメモリーの設計とMoatの考え方
itarutomy
0
150
Scaling your build logic
antalmonori
1
100
Androidアプリのモジュール分割における:x:commonを考える
okuzawats
1
280
Featured
See All Featured
It's Worth the Effort
3n
183
28k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
29
960
Producing Creativity
orderedlist
PRO
343
39k
VelocityConf: Rendering Performance Case Studies
addyosmani
327
24k
Fashionably flexible responsive web design (full day workshop)
malarkey
406
66k
The Pragmatic Product Professional
lauravandoore
32
6.4k
jQuery: Nuts, Bolts and Bling
dougneiner
62
7.6k
For a Future-Friendly Web
brad_frost
176
9.5k
Measuring & Analyzing Core Web Vitals
bluesmoon
5
210
Principles of Awesome APIs and How to Build Them.
keavy
126
17k
How to train your dragon (web standard)
notwaldorf
89
5.8k
4 Signs Your Business is Dying
shpigford
182
22k
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