我有一个很大的数组,我想通过将它的片段交给一些异步任务来处理。作为概念证明,我编写了以下代码:
class TestParallelArrayProcessing { let array: [Int] var summary: [Int] init() { array = Array<Int>(count: 500000, repeatedValue: 0) for i in 0 ..< 500000 { array[i] = Int(arc4random_uniform(10)) } summary = Array<Int>(count: 10, repeatedValue: 0) } func calcSummary() { let group = dispatch_group_create() let queue = dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0) for i in 0 ..< 10 { dispatch_group_async(group, queue, { let base = i * 50000 for x in base ..< base + 50000 { self.summary[i] += self.array[x] } }) } dispatch_group_notify(group, queue, { println(self.summary) }) } }
之后init(),array将使用0到9之间的随机整数初始化。
init()
array
该calcSummary函数array使用它们各自的插槽summary作为累加器,分派10个任务,这些任务从50000个项目的不相交的块中将它们相加并相加。
calcSummary
summary
该程序self.summary[i] += self.array[x]在行崩溃。错误是:
self.summary[i] += self.array[x]
EXC_BAD_INSTRUCTION (code = EXC_I386_INVOP).
我可以看到,在调试器中,它在崩溃前已经进行了几次迭代,并且在崩溃时变量具有正确范围内的值。
我读过EXC_I386_INVOP尝试访问已发布的对象时可能发生的情况。我想知道这是否与Swift修改数组是否有关系,如果是的话,如何避免它。
EXC_I386_INVOP
这与@Eduardo的答案中使用Array类型withUnsafeMutableBufferPointer<R>(body: (inout UnsafeMutableBufferPointer<T>) -> R) -> R方法的方法稍有不同。该方法的文档指出:
Array
withUnsafeMutableBufferPointer<R>(body: (inout UnsafeMutableBufferPointer<T>) -> R) -> R
Call body(p),其中p是指向Array的可变连续存储的指针。如果不存在这样的存储,则会首先创建它。 通常,优化程序可以消除数组算法中的边界检查和唯一性检查,但是当失败时,在body的参数上调用相同的算法可以让您以安全为代价。
Call body(p),其中p是指向Array的可变连续存储的指针。如果不存在这样的存储,则会首先创建它。
body(p)
p
通常,优化程序可以消除数组算法中的边界检查和唯一性检查,但是当失败时,在body的参数上调用相同的算法可以让您以安全为代价。
body
第二段似乎正是这里发生的情况,因此在Swift中使用此方法可能更“惯用”,无论是什么意思:
func calcSummary() { let group = dispatch_group_create() let queue = dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0) self.summary.withUnsafeMutableBufferPointer { summaryMem -> Void in for i in 0 ..< 10 { dispatch_group_async(group, queue, { let base = i * 50000 for x in base ..< base + 50000 { summaryMem[i] += self.array[x] } }) } } dispatch_group_notify(group, queue, { println(self.summary) }) }