Arrayはスレッドセーフなのか?
通常、スレッドセーフとして作られているならばそうドキュメントに書いてあります。
しかし、Swiftのドキュメントにはそのようなことは書いてありません。
そのためArray型はスレッドセーフでない、と考えるべきです。
はい、終了。
Copy-on-writeはスレッドセーフ?
待てよ?SwiftのArrayはCopy-on-Writeっていう仕組みがあるんだよな?
そうすると別の変数でも実体は同じインスタンスを指している可能性がある。
それじゃあ別々のスレッドからアクセスするには明示的に別インスタンスとして生成しないとまずいんじゃないの?
let a = [1,2,3]
let b = [Int](a)
こんな風に書かないといけない?めんどくさっ
(というかこれで本当に別インスタンスになるのだろうか?)
と思いましたが、
Value and Reference Types - Swift Blog - Apple Developer
In Swift, Array, String, and Dictionary are all value types. They behave much like a simple int value in C, acting as a unique instance of that data. You don’t need to do anything special — such as making an explicit copy — to prevent other code from modifying that data behind your back. Importantly, you can safely pass copies of values across threads without synchronization. In the spirit of improving safety, this model will help you write more predictable code in Swift.
適当訳(最後めんどくなってGoogle翻訳しちゃった)
SwiftではArray, String, Dictionaryなどは値型です。これらはCでの単純なint型と同じように振る舞い、事実上データのユニークなインスタンスです。裏でデータを変更する処理が走っていても特別なこと(明示的にコピーを作る等)をする必要はありません。重要なことは同期を取ることなく安全にスレッド間で値のコピーを渡すことができることです。安全性向上の精神では、このモデルではSwiftでより予測しやすいコードを書くのに役立ちます。
ということで、Copy-on-Write自体はスレッドセーフかはわかりませんが、Array等が実装しているCopy-on-Writeはスレッドセーフになってるみたいです。
値型として考えると自然な動作になるようしてるんですね。
余談ですがCopy-on-Writeを実装するならスレッドセーフにするよう推奨してるっぽいですね。
結論
- Array自体はスレッドセーフでない
- ArrayのCopy-on-Write実装はスレッドセーフ
- 同じ変数に格納されたArrayを複数スレッドからアクセスするときは同期とっとけ
- 別の変数に保持してあれば別スレッドからアクセスしても大丈夫
var a = [1,2,3]
DispatchQueue.global().async {
a.append(5)
}
DispatchQueue.global().async {
a.append(6)
}
var a = [1,2,3]
var b = a
DispatchQueue.global().async {
a.append(5)
}
DispatchQueue.global().async {
b.append(6)
}
参考
Is swift array thread safe? Can swift array face race condition? : swift
Value and Reference Types - Swift Blog - Apple Developer
The Swift Programming Language (Swift 3): Collection Types