【发布时间】:2020-02-01 07:39:27
【问题描述】:
我正在尝试创建一个线程安全的属性包装器。我只能认为 GCD 队列和信号量是最 Swifty 和最可靠的方式。信号量只是性能更高(如果这是真的),还是有其他理由使用一个而不是另一个来实现并发?
以下是原子属性包装器的两种变体:
@propertyWrapper
struct Atomic<Value> {
private var value: Value
private let queue = DispatchQueue(label: "Atomic serial queue")
var wrappedValue: Value {
get { queue.sync { value } }
set { queue.sync { value = newValue } }
}
init(wrappedValue value: Value) {
self.value = value
}
}
@propertyWrapper
struct Atomic2<Value> {
private var value: Value
private var semaphore = DispatchSemaphore(value: 1)
var wrappedValue: Value {
get {
semaphore.wait()
let temp = value
semaphore.signal()
return temp
}
set {
semaphore.wait()
value = newValue
semaphore.signal()
}
}
init(wrappedValue value: Value) {
self.value = value
}
}
struct MyStruct {
@Atomic var counter = 0
@Atomic2 var counter2 = 0
}
func test() {
var myStruct = MyStruct()
DispatchQueue.concurrentPerform(iterations: 1000) {
myStruct.counter += $0
myStruct.counter2 += $0
}
}
如何正确测试和测量它们以了解两种实现之间的差异以及它们是否有效?
【问题讨论】:
-
根据这个讨论,写入是安全的,但读取是陈旧的:forums.swift.org/t/whats-the-state-of-modify-yield/29171
-
如果您使用相同的名称,所有包装变量将使用相同的队列。写入可以是异步的,读取可以是并发的。 (这可以通过在写入时传递屏障标志并使用并发队列来完成。)
-
队列的名称对指定使用哪个队列没有影响。他们还是不同的。我相信该名称仅用于堆栈跟踪目的。
标签: swift concurrency grand-central-dispatch semaphore