2015-11-04 68 views
4

我使用Grand Central Dispatch將一個數組的元素轉換爲另一個數組。我在源數組上調用dispatch_apply,將其轉換爲零個或多個項目,然後將它們添加到目標數組中。這是一個簡單的例子:並行添加到數組

let src = Array(0..<1000) 
var dst = [UInt32]() 

let queue = dispatch_queue_create("myqueue", DISPATCH_QUEUE_CONCURRENT) 
dispatch_apply(src.count, queue) { i in 
    dst.append(arc4random_uniform(UInt32(i))) // <-- potential error here 
} 

print(dst) 

有時坐上append線的錯誤。該錯誤是始終之一:

1. malloc: *** error for object 0x107508f00: pointer being freed was not allocated 
2. fatal error: UnsafeMutablePointer.destroy with negative count 
3. fatal error: Can't form Range with end < start 

我想這是由於append不是線程安全的。我做錯了什麼以及如何解決?

+0

比較http://stackoverflow.com/questions/26693838/process-array-in-parallel-using-gcd。 –

+0

感謝@MartinR。這個問題改變了數組的現有值,而不是追加到它。 'withUnsafeMutablePointer'沒有'append'方法 – Jenny

+0

正如你已經注意到的,append()不是線程安全的。您可能必須先創建必要大小的數組。然後你可以使用引用的Q&A中的方法從多個線程並行地填充數組。 –

回答

3

正如您發現的那樣,Swift可能會重新定位陣列以提高內存效率。當你運行多個append時,它肯定會發生。我的猜測是,與轉換相比,追加到陣列的成本是非常低的。您可以創建一個串行隊列只是延長dst陣列:

let src = Array(0..<1000) 
var dst = [UInt32]() 

let queue = dispatch_queue_create("myqueue", DISPATCH_QUEUE_CONCURRENT) 
let serialQueue = dispatch_queue_create("mySerialQueue", DISPATCH_QUEUE_SERIAL) 
let serialGroup = dispatch_group_create() 

dispatch_apply(src.count, queue) { i in 
    let result = arc4random_uniform(UInt32(i)) // Your long-running transformation here 
    dispatch_group_async(serialGroup, serialQueue) { 
     dst.append(result) 
    } 
} 

// Wait until all append operations are complete 
dispatch_group_wait(serialGroup, DISPATCH_TIME_FOREVER) 
+0

爲什麼使用'dispatch_group_async'而不是'group_async'? – Jenny

+0

我認爲你的意思是'dispatch_group_async'與'dispatch_async'。原因是你可以等第一個,但不是第二個功能。 –

+0

我有這個相同的問題,但我不認爲這將是如此複雜的XD謝謝你的解決方案! –