繁体   English   中英

并行数组元素分配导致 Swift 崩溃

[英]Parallel array elements assignment causes crash in Swift

我想同时设置数组的元素,所以我编写代码来测试:

let Count = 1000
let SubRangeCount = 100
var ary = [Int](repeating: 0, count: Count)

let times = Count/SubRangeCount
let _ = DispatchQueue.global(qos: .userInitiated)
DispatchQueue.concurrentPerform(iterations: times){ idx in
        for i in (idx * SubRangeCount)..<((idx+1) * SubRangeCount) {
            ary[i] = Int.random(in: 0...Int.max)
        }
    }
}

上面的代码工作得很好:但是当我这样改变时:

let Count = 10000
let SubRangeCount = 1000

它崩溃了:在操场上它抱怨“致命错误。UnsafeMutablePointer:初始化重叠范围。文件 Swift/UnsafePointer,swift,第 832 行”

但是您可以看到数组分配的每个范围都没有重叠!

那么如何解决呢? 谢谢!

Array在 Swift 上不是线程安全的,因此您需要同步对它的访问,例如使用objc_sync_enterobjc_sync_exit

func synchronized<T : AnyObject, U>(_ obj: T, closure: () -> U) -> U {
    objc_sync_enter(obj)
    defer {
        objc_sync_exit(obj)
    }
    return closure()
}

var arr = [Int](repeating: 0, count: 100_000)
let obj = arr as NSObject // Object to synchronise

DispatchQueue.concurrentPerform(iterations: 100_000){ index in
    synchronized(obj) {
        arr[index] = Int.random(in: 0...Int.max)
    }
}

这里数组是从多个线程同时变异的,这会产生竞争条件。 为避免这种情况,您必须以线程安全的方式执行关键操作。 您可以从 Apple 平台中的 Grand Central Dispatch 获得帮助——它让我们可以使用其更简单的基于队列的抽象来处理线程。

let Count = 10000
let SubRangeCount = 1000
var ary = [Int](repeating: 0, count: Count)

let times = Count/SubRangeCount
let serialQueue = DispatchQueue(label: "serial.Queue")
DispatchQueue.concurrentPerform(iterations: times){ idx in
    print(idx)
    for i in (idx * SubRangeCount)..<((idx+1) * SubRangeCount) {
        serialQueue.async {
            ary[i] = Int.random(in: 0...Int.max)
        }
    }
}

您也可以使用锁。

let Count = 10000
let SubRangeCount = 1000
var ary = [Int](repeating: 0, count: Count)
let lock = NSLock()

let times = Count/SubRangeCount
DispatchQueue.concurrentPerform(iterations: times){ idx in
    print(idx)
    for i in (idx * SubRangeCount)..<((idx+1) * SubRangeCount) {
        lock.lock()
        ary[i] = Int.random(in: 0...Int.max)
        lock.unlock()
    }
}

我找到了解决方法:

DispatchQueue.concurrentPerform(iterations: enumTimes){ idx in
    
    var subAry = ary1[(idx * SubRangeCount)..<((idx+1) * SubRangeCount)]
    
    for i in subAry.indices {
        subAry[i] = Int.random(in: 0...Int.max)
    }
}

它没有崩溃,并且比序列化作业快 3 到 10 倍。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM