我刚刚阅读了a post by Basem Emara关于创建一个线程安全数组类型的Swift。当我浏览代码示例时,我问自己是否有一种方法可以用更少的代码来实现这一点。
假设我创建了这个类:
// MARK: Class Declaration
class ThreadsafeArray<Element> {
// Private Variables
private var __array: [Element] = []
private var __arrayQueue: DispatchQueue = DispatchQueue(
label: "ThreadsafeArray.__concurrentArrayQueue",
attributes: .concurrent
)
}
// MARK: Interface
extension ThreadSafeArray {
// ReadWrite Variables
var threadsafe: [Element] {
get {
return self.__arrayQueue.sync {
return self.__array
}
}
set(newArray) {
self.__arrayQueue.async(flags: .barrier) {
self.__array = newArray
}
}
}
}
从现在开始,我只通过.threadsafe
访问了实际数组,这是否足以使数组线程安全?
另外,我可以将它实现为结构而不是类来获取变异检查吗?
我知道这个数组中的对象本身并不是线程安全的,但这不是重点,所以我们假设我只把线程安全的东西放在那里。
(当然,为了避免调用.threadsafe
,我会让闪亮的新类符合ExpressibleByArrayLiteral
,Collection
和RangeReplaceableCollection
,因此我可以使用它像一个普通的数组。
与此同时,我已经尝试过测试它in a playground并开始相信它不够。
import Foundation
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
// Testing //
// Thread-unsafe array
func unsafeArray() {
var array: [Int] = []
var iterations: Int = 1000
let start: TimeInterval = Date().timeIntervalSince1970
DispatchQueue.concurrentPerform(iterations: iterations) { index in
let last: Int = array.last ?? 0
array.append(last + 1)
DispatchQueue.global().sync {
iterations -= 1
// Final loop
guard iterations <= 0 else { return }
print(String(
format: "Unsafe loop took %.3f seconds, count: %d.",
Date().timeIntervalSince1970 - start, array.count
))
}
}
}
// Thread-safe array
func safeArray() {
let array: ThreadsafeArray<Int> = ThreadsafeArray<Int>()
var iterations: Int = 1000
let start: TimeInterval = Date().timeIntervalSince1970
DispatchQueue.concurrentPerform(iterations: iterations) { index in
let last: Int = array.threadsafe.last ?? 0
array.threadsafe.append(last + 1)
DispatchQueue.global().sync {
iterations -= 1
// Final loop
guard iterations <= 0 else { return }
print(String(
format: "Safe loop took %.3f seconds, count: %d.",
Date().timeIntervalSince1970 - start, array.threadsafe.count
))
}
}
}
unsafeArray()
safeArray()
大部分时间:
experiments(31117,0x7000038d0000) malloc: *** error for object 0x11f663d28: pointer being freed was not allocated
***在malloc_error_break中设置断点以进行调试
有时:
IndexError: Index out of range
不幸的是:
Unsafe loop took 1.916 seconds, count: 994.
Safe loop took 11.258 seconds, count: 515.
似乎不够(也是,它非常难以理解)。
答案 0 :(得分:0)
我怀疑这是您的问题:
DispatchQueue.global().sync { ...
如果在此处指定要使用的一个串行队列,则应获得所需的结果。
类似的东西:
let array = SynchronizedArray<Int>()
var iterations = 1000
let queue = DispatchQueue(label: "queue")
DispatchQueue.concurrentPerform(iterations: 1000) { index in
array.append(array.last ?? 0)
queue.sync {
iterations -= 1
if iterations == 0 {
print(array.count)
}
}
}
答案 1 :(得分:-1)
另一种锁定对象的方法是:
func lock(obj: AnyObject, work:() -> ()) {
objc_sync_enter(obj)
work()
objc_sync_exit(obj)
}
您的班级可以在需要时使用它来锁定其标准数组吗?