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
810
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Swift Concurrencyとレースコンディション
After iOSDC Japan 2024
2024/8/26
Yuki Yasoshima
August 25, 2024
More Decks by Yuki Yasoshima
See All by Yuki Yasoshima
空間オーディオの活用
objectiveaudio
0
190
Swift Concurrency - 状態監視の罠
objectiveaudio
2
860
モーダルの遷移を理解する
objectiveaudio
4
2.8k
オーディオ波形を表示するために知っておくべきこと
objectiveaudio
0
1.1k
AVAudioEngineでリアルタイムレンダリング
objectiveaudio
1
950
リファクタリング・チャレンジ リバーシ編
objectiveaudio
0
210
UIKitは2度ベルを鳴らす
objectiveaudio
0
370
iOSDC2018.pdf
objectiveaudio
1
2.4k
Objective-C++を使ってMRCで快適に開発する
objectiveaudio
0
24k
Other Decks in Programming
See All in Programming
まずはプロンプトガイドを読もう、話はそれからだ
kiakiraki
1
150
改善しないと、タスクが回らない。 “てんこ盛りポジション” を引き継いだ情シスの、入社3ヶ月の業務改善録
krm963
0
280
Terraform標準の組織で AWS CDKをどう使うか
mu7889yoon
1
540
ドリフトを絶対に許さない(?)CDK運用 / CDK Ops with Zero Tolerance for Drifts (?)
akihisaikeda
1
210
jsmini JavaScript Engine を作ってみた話
yosuke_furukawa
PRO
0
340
MySQLとPostgreSQLって何が違うの?
akagami
0
120
What's New in Android 2026
veronikapj
0
270
Pythonの実行はどこまで賢くなったのか? CPythonとPyPyから見る最適化のしくみ
curekoshimizu
0
130
Claude Code全社展開のためにやったことn選~プラグイン302個・コミッター271人を支えるために~
kenchan
5
1.6k
PHP に部分適用が来るぞ!……ところで何それ?おいしいの? #phpcon / phpcon-2026
shogogg
0
710
AIが無かった頃の素敵な出会いの話
codmoninc
1
470
人間の目はかわらない、だからJPEGは30年もつ
yuzneri
12
19k
Featured
See All Featured
The agentic SEO stack - context over prompts
schlessera
0
870
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.6k
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
68
57k
How to optimise 3,500 product descriptions for ecommerce in one day using ChatGPT
katarinadahlin
PRO
2
3.8k
Have SEOs Ruined the Internet? - User Awareness of SEO in 2025
akashhashmi
0
420
KATA
mclloyd
PRO
35
15k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
21
1.6k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
47
8.3k
Making Projects Easy
brettharned
120
6.7k
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
Rebuilding a faster, lazier Slack
samanthasiow
85
9.6k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
659
62k
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