我发现以下代码(在Playground上运行)有一个奇怪的行为。
import Foundation
let count = 100
var array = [[Int]](repeating:[Int](), count:count)
DispatchQueue.concurrentPerform(iterations: count) { (i) in
array[i] = Array(i..<i+count)
}
// Evaluation
for (i,value) in array.enumerated() {
if (value.count != count) {
print(i, value.count)
}
}
每次的结果都不同,有时会因内存损坏而崩溃。似乎在另一个线程访问内存时正在发生(“数组”的)内存重新分配。
这是(iOS的)错误还是预期的行为?我想念什么吗?
答案 0 :(得分:2)
这是预期的行为。 Swift数组不是线程安全的;也就是说,同时修改多个线程的Swift数组会导致损坏。
我意识到您只是在做实验,但是即使数组是线程安全的,也不能很好地使用concurrentPerform
,并且考虑到线程开销,它可能比简单的for
循环性能差
一旦您引入了适当的同步方法来保护阵列更新,例如将更新分派到串行分派队列中,它肯定会比简单的for
循环更慢执行< / p>
答案 1 :(得分:0)
这是解决方案。感谢您的快速回复。
import Foundation
let count = 1000
var arrays = [[Int]](repeating:[Int](), count:count)
let dispatchGroup = DispatchGroup()
let lockQueue = DispatchQueue(label: "lockQueue")
DispatchQueue.concurrentPerform(iterations: count) { (i) in
dispatchGroup.enter()
let array = Array(i..<i+count) // The actual code is very complex
lockQueue.async {
arrays[i] = array
dispatchGroup.leave()
}
}
dispatchGroup.wait()
// Evaluation
for (i,value) in arrays.enumerated() {
if (value.count != count) {
print(i, value.count)
}
}
答案 2 :(得分:0)
在我的情况下,我不得不每秒Float
多次生成24k元素数组,而在旧版iPhone 6上,每个数组花费大约40ms。
由于数组的每个元素只分配了一次,所以我决定尝试使用指针来处理原始数组:
class UnsafeArray<T> {
let count: Int
let cArray: UnsafeMutablePointer<T>
init(_ size: Int) {
count = size
cArray = UnsafeMutablePointer<T>.allocate(capacity: size)
}
subscript(index: Int) -> T {
get { return cArray[index] }
set { cArray[index] = newValue }
}
deinit {
free(cArray)
}
}
然后我像这样使用它:
let result = UnsafeArray<Float>(24000)
DispatchQueue.concurrentPerform(iterations: result.count, execute: { i in
result[i] = someCalculation()
})
它奏效了!现在需要9到16毫秒。另外,使用此代码也不会造成内存泄漏。