DispatchQueue threads don't always set the correct results - ios

Am trying on coding game MineSweeper, the following code is to set the numbers around landmines. For a test, I choose the minimum level 9 x 9 with 10 landmines.
For a faster performance, I tried to use more threads when setting numbers, but one day I found that it doesn't always give the correct number arrangements, I made a loop to create it 1000 times and found that 20 ~ 40 out of 1000 are wrong.
Here are several wrong results, "*" represents landmine, "0" means no landmine around
wrong mine: index 1 should be "*"
10212*100
112*21211
0011101*1
000000111
000011100
01123*200
01*2**200
023432100
01**10000
wrong num: index 0 should be "1"
0*212*100
112*21211
0011101*1
000000111
000011100
01123*200
01*2**200
023432100
01**10000
wrong num: index 73 should be "1"
1*212*100
112*21211
0011101*1
000000111
000011100
01123*200
01*2**200
023432100
00**10000
Without using DispatchQueue or set DispatchSemaphore's value to 1, it gives the correct number arrangement in 1000%1000.
1*212*100
112*21211
0011101*1
000000111
000011100
01123*200
01*2**200
023432100
01**10000
Here is the sample code:
// actually indexes created randomly every time
let minesIndexArr = [59, 74, 1, 12, 50, 56, 75, 58, 5, 25]
var defaultCellArr = [String]()
var totalCellArr = [String]()
var count = 0
for _ 1...81 {
defaultCellArr.append("0")
}
runLoop()
func runLoop() {
if count == 1000 {
return
}
totalCellArr = defaultCellArr
setNums()
}
func setNums() {
let group = DispatchGroup()
let queue = DispatchQueue(label: "com.setnums", attributes: .concurrent)
let semaphore = DispatchSemaphore(value: 10)
for i in 0..<self.totalCellArr.count {
semaphore.wait()
group.enter()
queue.async(group: group, execute: {
if self.minesIndexArr.firstIndex(of: i) != nil{
self.totalCellArr[i] = "*"
}else{
var num = 0
let neighbourIndexes = self.getNeighbourIndex(i)
for v in neighbourIndexes.values {
if self.minesIndexArr.firstIndex(of: v) != nil {
num += 1
}
}
self.totalCellArr[i] = String(num)
}
group.leave()
semaphore.signal()
})
}
group.notify(queue: DispatchQueue.main) {
printMap()
count += 1
self.runLoop()
}
}

tl;dr
You are using this non-zero semaphore to do parallel calculations, constraining the degree of concurrency to something reasonable. I would recommend concurrentPerform.
But the issue here is not how you are constraining the degree of the parallelism, but rather that you are using the same properties (shared by all of these concurrent tasks) for your calculations, which means that one iteration on one thread can be mutating these properties while they are being used/mutated by another parallel iteration on another thread.
So, I would avoid using any shared properties at all (short of the final array of boards). Use local variables only. And make sure to synchronize the updating of this final array so that you don't have two threads mutating it at the same time.
So, for example, if you wanted to create the boards in parallel, I would probably use concurrentPerform as outlined in my prior answer:
func populateBoards(count: Int, rows: Int, columns: Int, mineCount: Int, completion: #escaping ([Board]) -> Void) {
var boards: [Board] = []
let lock = NSLock()
DispatchQueue.global().async {
DispatchQueue.concurrentPerform(iterations: count) { index in
let board = Board(rows: rows, columns: columns, mineCount: mineCount)
lock.synchronize {
boards.append(board)
}
}
}
DispatchQueue.main.async {
lock.synchronize {
completion(boards)
}
}
}
Note, I'm not referencing any ivars. It is all local variables, passing the result back in a closure.
And to avoid race conditions where multiple threads might be trying to update the same array of boards, I am synchronizing my access with a NSLock. (You can use whatever synchronization mechanism you want, but locks a very performant solution, probably better than a GCD serial queue or reader-writer pattern in this particular scenario.) That synchronize method is as follows:
extension NSLocking {
func synchronize<T>(block: () throws -> T) rethrows -> T {
lock()
defer { unlock() }
return try block()
}
}
That is a nice generalized solution (handling closures that might return values, throw errors, etc.), but if that is too complicated to follow, here is a minimalistic rendition that is sufficient for our purposes here:
extension NSLocking {
func synchronize(block: () -> Void) {
lock()
block()
unlock()
}
}
Now, I confess, that I'd probably employ a different model for the board. I would define a Square enum for the individual squares of the board, and then define a Board which was an array (for rows) of arrays (for columns) for all these squares. Anyway, this in my implementation of the Board:
enum Square {
case count(Int)
case mine
}
struct Board {
let rows: Int
let columns: Int
var squares: [[Square]]
init(rows: Int, columns: Int, mineCount: Int) {
self.rows = rows
self.columns = columns
// populate board with all zeros
self.squares = (0..<rows).map { _ in
Array(repeating: Square.count(0), count: columns)
}
// now add mines
addMinesAndUpdateNearbyCounts(mineCount)
}
mutating func addMinesAndUpdateNearbyCounts(_ mineCount: Int) {
let mines = (0..<rows * columns)
.map { index in
index.quotientAndRemainder(dividingBy: columns)
}
.shuffled()
.prefix(mineCount)
for (mineRow, mineColumn) in mines {
squares[mineRow][mineColumn] = .mine
for row in mineRow-1 ... mineRow+1 where row >= 0 && row < rows {
for column in mineColumn-1 ... mineColumn+1 where column >= 0 && column < columns {
if case .count(let n) = squares[row][column] {
squares[row][column] = .count(n + 1)
}
}
}
}
}
}
extension Board: CustomStringConvertible {
var description: String {
var result = ""
for row in 0..<rows {
for column in 0..<columns {
switch squares[row][column] {
case .count(let n): result += String(n)
case .mine: result += "*"
}
}
result += "\n"
}
return result
}
}
Anyway, I would generate 1000 9×9 boards with ten mines each like so:
exercise.populateBoards(count: 1000, rows: 9, columns: 9, mineCount: 10) { boards in
for board in boards {
print(board)
print("")
}
}
But feel free to use whatever model you want. But I'd suggest encapsulating the model for the Board in its own type. It not only abstracts the details of the generation of a board from the multithreaded algorithm to create lots of boards, but it naturally avoids any unintended sharing of properties by the various threads.
Now all of this said, this is not a great example of parallelized code because the creation of a board is not nearly computationally intensive enough to justify the (admittedly very minor) overhead of running it in parallel. This is not a problem that is likely to benefit much from parallelized routines. Maybe you'd see some modest performance improvement, but not nearly as much as you might experience from something a little more computationally intensive.

Related

How to use firstIndex in Switft to find all results

I am trying to split a string into an array of letters, but keep some of the letters together. (I'm trying to break them into sound groups for pronunciation, for example).
So, for example, all the "sh' combinations would be one value in the array instead of two.
It is easy to find an 's' in an array that I know has an "sh" in it, using firstIndex. But how do I get more than just the first, or last, index of the array?
The Swift documentation includes this example:
let students = ["Kofi", "Abena", "Peter", "Kweku", "Akosua"]
if let i = students.firstIndex(where: { $0.hasPrefix("A") }) {
print("\(students[i]) starts with 'A'!")
}
// Prints "Abena starts with 'A'!"
How do I get both Abena and Akosua (and others, if there were more?)
Here is my code that accomplishes some of what I want (please excuse the rather lame error catching)
let message = "she sells seashells"
var letterArray = message.map { String($0)}
var error = false
while error == false {
if message.contains("sh") {
guard let locate1 = letterArray.firstIndex(of: "s") else{
error = true
break }
let locate2 = locate1 + 1
//since it keeps finding an s it doesn't know how to move on to rest of string and we get an infinite loop
if letterArray[locate2] == "h"{
letterArray.insert("sh", at: locate1)
letterArray.remove (at: locate1 + 1)
letterArray.remove (at: locate2)}}
else { error = true }}
print (message, letterArray)
Instead of first use filter you will get both Abena and Akosua (and others, if there were more?)
extension Array where Element: Equatable {
func allIndexes(of element: Element) -> [Int] {
return self.enumerated().filter({ element == $0.element }).map({ $0.offset })
}
}
You can then call
letterArray.allIndexes(of: "s") // [0, 4, 8, 10, 13, 18]
You can filter the collection indices:
let students = ["Kofi", "Abena", "Peter", "Kweku", "Akosua"]
let indices = students.indices.filter({students[$0].hasPrefix("A")})
print(indices) // "[1, 4]\n"
You can also create your own indices method that takes a predicate:
extension Collection {
func indices(where predicate: #escaping (Element) throws -> Bool) rethrows -> [Index] {
try indices.filter { try predicate(self[$0]) }
}
}
Usage:
let indices = students.indices { $0.hasPrefix("A") }
print(indices) // "[1, 4]\n"
or indices(of:) where the collection elements are Equatable:
extension Collection where Element: Equatable {
func indices(of element: Element) -> [Index] {
indices.filter { self[$0] == element }
}
}
usage:
let message = "she sells seashells"
let indices = message.indices(of: "s")
print(indices)
Note: If you need to find all ranges of a substring in a string you can check this post.
Have fun!
["Kofi", "Abena", "Peter", "Kweku", "Akosua"].forEach {
if $0.hasPrefix("A") {
print("\($0) starts with 'A'!")
}
}
If you really want to use the firstIndex method, here's a recursive(!) implementation just for fun :D
extension Collection where Element: Equatable {
/// Returns the indices of an element from the specified index to the end of the collection.
func indices(of element: Element, fromIndex: Index? = nil) -> [Index] {
let subsequence = suffix(from: fromIndex ?? startIndex)
if let elementIndex = subsequence.firstIndex(of: element) {
return [elementIndex] + indices(of: element, fromIndex: index(elementIndex, offsetBy: 1))
}
return []
}
}
Recursions
Given n instances of element in the collection, the function will be called n+1 times (including the first call).
Complexity
Looking at complexity, suffix(from:) is O(1), and firstIndex(of:) is O(n). Assuming that firstIndex terminates once it encounters the first match, any recursions simply pick up where we left off. Therefore, indices(of:fromIndex:) is O(n), just as good as using filter. Sadly, this function is not tail recursive... although we can change that by keeping a running total.
Performance
[Maybe I'll do this another time.]
Disclaimer
Recursion is fun and all, but you should probably use Leo Dabus' solution.

Is my recursive function failing due to a stack overflow? If yes, given my function definition, is it normal?

I was testing a recursive function for performance.
In line 33, I create an array with 50,000 items in it; each item in the array is an Int between 1 & 30.
The test crashes when the array has a count approximately > 37500.
I’m not exactly sure what this crash is due to, but my guess is that it’s due to a stack overflow?
Is it in fact due to stackover flow?
Given what I’m doing / this context - is a stack overflow here normal to expect?
The code is provided below for your convenience:
let arr = (1...50000).map { _ in Int.random(in: 1...30) }
func getBuildingsWithView(_ buildings: [Int]) -> [Int]? {
if buildings.isEmpty { return nil }
let count: Int = buildings.count - 1
var indices: [Int] = []
let largest: Int = 0
var buildings = buildings
hasView(&buildings, &indices, largest, count)
return indices
}
func hasView(_ buildings: inout [Int], _ indices: inout [Int], _ largest: Int, _ count: Int) {
if count > 0 {
var largest = largest
if (buildings[count] > largest) {
largest = buildings[count]
}
hasView(&buildings, &indices, largest, count-1)
}
if (buildings[count] > largest) {
indices.append(count)
}
}
func test1() {
print("-----------------TEST START - RECURSION------------------")
measure {
print(getBuildingsWithView(arr)!)
}
print("-----------------END------------------")
}
This is likely a stack overflow, function hasView is called cursively with a depth roughly equal to count and the stack has to store count adresses which could exceed the stack size for huge numbers.
More details in another post: BAD_ACCESS during recursive calls in Swift
Please note that what you implemented seems to be a running maximum in reverse order returning the indices and this can implemented more efficiently without overflow like this:
func runningMax(_ arr: [Int]) -> [Int] {
var max = 0
var out = [Int]()
for (i, element) in arr.enumerated().reversed() {
if element > max {
max = element
out.append(i)
}
}
return out.reversed()
}
I compared this with your algorithm and the outputs seems to be identical. I also tested with larges values up to 100,000,000 and it is fine.
Returned array does not need to be optional, if the input array is empty so do the output array.

Corrupted memory with DispatchQueue.concurrentPerform

I see a strange behavior with the following code (which runs on 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)
}
}
The result is different each time, and sometime crashes with memory corruption. It looks like a memory reallocation (of "array") is happening while another thread is accessing the memory.
Is this a bug (of iOS) or an expected behavior? Am I missing something?
This is expected behaviour. Swift arrays are not thread safe; That is, modifying a Swift array from multiple threads concurrently will cause corruption.
I realise that you are just experimenting, but even if arrays were thread safe, this would not be a good use of concurrentPerform and would probably perform worse than a simple for loop given the threading overhead.
Once you introduce an appropriate synchronisation method to guard the array update, such as dispatching that update onto a serial dispatch queue, it will definitely perform more slowly than a simple for loop
Here is the solution. Thank you for quick responses.
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)
}
}
In my case I had to generate 24k elements array with Float multiple times per second and it takes around 40ms for each on old iPhone 6.
Since each element of the array is only assigned once, I've decided to try raw array using pointers:
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)
}
}
Then I used it like this:
let result = UnsafeArray<Float>(24000)
DispatchQueue.concurrentPerform(iterations: result.count, execute: { i in
result[i] = someCalculation()
})
And it worked! Now it takes 9-16ms. Also, I have no memory leaks using this code.

Performance issue while finding min and max with functional approach

I have an array of subviews and I want to find the lowest tag and the highest tag (~ min and max). I tried to play with the functional approach of Swift and optimized it as much as my knowledge allowed me, but when I do this:
let startVals = (min:Int.max, max:Int.min)
var minMax:(min: Int, max: Int) = subviews.filter({$0 is T2GCell}).reduce(startVals) {
(min($0.min, $1.tag), max($0.max, $1.tag))
}
I still get worse performance (approximately 10x slower) than good ol' for cycle:
var lowest2 = Int.max
var highest2 = Int.min
for view in subviews {
if let cell = view as? T2GCell {
lowest2 = lowest2 > cell.tag ? cell.tag : lowest2
highest2 = highest2 < cell.tag ? cell.tag : highest2
}
}
To be totally precise I am also including snippet of the measuring code. Note that the "after-recalculations" for human readable times is done outside of any measurement:
let startDate: NSDate = NSDate()
// code
let endDate: NSDate = NSDate()
// outside of measuring block
let dateComponents: NSDateComponents = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!.components(NSCalendarUnit.CalendarUnitNanosecond, fromDate: startDate, toDate: endDate, options: NSCalendarOptions(0))
let time = Double(Double(dateComponents.nanosecond) / 1000000.0)
My question is - am I doing it wrong, or this use case is simply not suitable for functional approach?
EDIT
This is is 2x slower:
var extremes = reduce(lazy(subviews).map({$0.tag}), startValues) {
(min($0.lowest, $1), max($0.highest, $1))
}
And this is only 20% slower:
var extremes2 = reduce(lazy(subviews), startValues) {
(min($0.lowest, $1.tag), max($0.highest, $1.tag))
}
Narrowed and squeezed down to very nice performance times, but still not as fast as the for cycle.
EDIT 2
I noticed I left out the filter in previous edits. When added:
var extremes3 = reduce(lazy(subviews).filter({$0 is T2GCell}), startValues) {
(min($0.lowest, $1.tag), max($0.highest, $1.tag))
}
I'm back to 2x slower performance.
In optimized builds, reduce and for should be completely equivalent in performance. However, in unoptimized debug builds, a for loop may beat the reduce version, because reduce will not be specialized and inlined. The filter can be removed, eliminating an unnecessary extra array creation, however that array creation is going to be pretty fast (all it is doing is copying pointers into memory) so that is not really a big deal, eliminating it is more for clarity.
However, I believe part of the problem is that in your reduce, you are calling the .tag property on AnyObject, whereas in your for loop version, you are calling T2GCell.tag. This could make a big difference. You can see this if you break out the filter:
// filtered will be of type [AnyObject]
let filtered = subviews.filter({$0 is T2GCell})
let minMax:(min: Int, max: Int) = filtered.reduce(startVals) {
// so $1.tag is calling AnyObject.tag, not T2GCell.tag
(min($0.min, $1.tag), max($0.max, $1.tag))
}
This means .tag is going to be dynamically bound at runtime, potentially a slower operation.
Here's some sample code that demonstrates the difference. If you compile this will swiftc -O you'll see the statically-bound (or rather not-quite-so dynamically-bound) reduce and the for loop perform pretty much the same:
import Foundation
#objc class MyClass: NSObject {
var someProperty: Int
init(_ x: Int) { someProperty = x }
}
let classes: [AnyObject] = (0..<10_000).map { _ in MyClass(Int(arc4random())) }
func timeRun<T>(name: String, f: ()->T) -> String {
let start = CFAbsoluteTimeGetCurrent()
let result = f()
let end = CFAbsoluteTimeGetCurrent()
let timeStr = toString(Int((end - start) * 1_000_000))
return "\(name)\t\(timeStr)µs, produced \(result)"
}
let runs = [
("Using AnyObj.someProperty", {
reduce(classes, 0) { prev,next in max(prev,next.someProperty) }
}),
("Using MyClass.someProperty", {
reduce(classes, 0) { prev,next in
(next as? MyClass).map { max(prev,$0.someProperty) } ?? prev
}
}),
("Using plain ol' for loop", {
var maxSoFar = 0
for obj in classes {
if let mc = obj as? MyClass {
maxSoFar = max(maxSoFar, mc.someProperty)
}
}
return maxSoFar
}),
]
println("\n".join(map(runs, timeRun)))
Output from this on my machine:
Using AnyObj.someProperty 4115µs, produced 4294310151
Using MyClass.someProperty 1169µs, produced 4294310151
Using plain ol' for loop 1178µs, produced 4294310151
Can't reproduce your exact example, but you can try moving away the filter. The following code should be functionally equivalent to your last attempt.
var extremes4 = reduce(subviews, startValues) {
$1 is T2GCell ? (min($0.lowest, $1.tag), max($0.highest, $1.tag)) : $0
}
Thus you don't iterate twice on subviews. Notice I removed lazy since it appears you always use the entire list.
By the way, IMHO, functional programming can be a very useful approach, but I would think twice before sacrificing code clarity for the only purpose of a fancy functional approach. Thus if a for loop is clearer, and even faster ... just use it ;-) That said, is good for you to experiment with different ways to approach the same problem.
One issue I could think of is that the looping is done twice. First the filter returns an filtered array and then a looping in reduce.
filter(_:)
Returns an array containing the elements of the array for which a provided closure indicates a match.
Declaration
func filter(includeElement: (T) -> Bool) -> [T]
Discussion
Use this method to return a new array by filtering an existing array. The closure that you supply for includeElement: should return a Boolean value to indicate whether an element should be included (true) or excluded (false) from the final collection:
While in the second case there is only one loop.
I am not sure if there is any difference of execution time for 'is' as 'as?' operator.

Counting number of Arrays that contain the same two values

Given a Dictionary<String, Arrary<Int>> find the how many entries have the same two specified values in the first 5 entries in the Array<Int>.
For example:
Given:
let numberSeries = [
"20022016": [07,14,36,47,50,02,05],
"13022016": [16,07,32,36,41,07,09],
"27022016": [14,18,19,31,36,04,05],
]
And the values: 7 and 36, the result should be 2 since the first and second entry have both the values 7 and 36 in the first 5 entries of the entry's array.
I've tried to accomplish this many ways, but I haven't been able to get it to work.
This is my current attempt:
//created a dictionary with (key, values)
let numberSeries = [
"20022016": [07,14,36,47,50,02,05],
"13022016": [16,07,32,36,41,07,09],
"27022016": [14,18,19,31,36,04,05],
]
var a = 07 //number to look for
var b = 36 // number to look for
// SearchForPairAB // search for pair // Doesn't Work.
var ab = [a,b] // pair to look for
var abPairApearedCount = 0
for (kind, numbers) in numberSeries {
for number in numbers[0...4] {
if number == ab { //err: Cannot invoke '==' with argument listof type Int, #Value [Int]
abPairApearedCount++
}
}
}
This gives the error: Cannot invoke '==' with argument listof type Int, #Value [Int] on the line: if number == ab
You can't use == to compare an Int and Array<Int>, that just doesn't make any sense from a comparison perspective. There are lots of different ways you can achieve what you're trying to do though. In this case I'd probably use map/reduce to count your pairs.
The idea is to map the values in your ab array to Bool values determined by whether or not the value is in your numbers array. Then, reduce those mapped Bools to a single value: true if they're all true, or false. If that reduced value is true, then we found the pair so we increment the count.
var ab = [a,b] // pair to look for
var abPairApearedCount = 0
for (kind, numbers) in numberSeries {
let found = ab.map({ number in
// find is a built-in function that returns the index of the value
// in the array, or nil if it's not found
return find(numbers[0...4], number) != nil
}).reduce(true) { (result, value: Bool) in
return result && value
}
if found {
abPairApearedCount++
}
}
That can actually be compacted quite a bit by using some of Swift's more concise syntax:
var ab = [a,b] // pair to look for
var abPairApearedCount = 0
for (kind, numbers) in numberSeries {
let found = ab.map({ find(numbers[0...4], $0) != nil }).reduce(true) { $0 && $1 }
if found {
abPairApearedCount++
}
}
And, just for fun, can be compacted even further by using reduce instead of a for-in loop:
var ab = [a,b] // pair to look for
var abPairApearedCount = reduce(numberSeries, 0) { result, series in
result + (ab.map({ find(series.1[0...4], $0) != nil }).reduce(true) { $0 && $1 } ? 1 : 0)
}
That's getting fairly unreadable though, so I'd probably expand some of that back out.
So here's my FP solution, aimed at decomposing the problem into easily digestible and reusable bite-sized chunks:
First, we define a functor that trims an array to a given length:
func trimLength<T>(length: Int) -> ([T]) -> [T] {
return { return Array($0[0...length]) }
}
Using this we can trim all the elements using map(array, trimLength(5))
Now, we need an predicate to determine if all the elements of one array are in the target array:
func containsAll<T:Equatable>(check:[T]) -> ([T]) -> Bool {
return { target in
return reduce(check, true, { acc, elem in return acc && contains(target, elem) })
}
}
This is the ugliest bit of code here, but essentially it's just iterating over check and insuring that each element is in the target array. Once we've got this we can use filter(array, containsAll([7, 26])) to eliminate all elements of the array that don't contain all of our target values.
At this point, we can glue the whole thing together as:
filter(map(numberSeries.values, trimLength(5)), containsAll([7, 36])).count
But long lines of nested functions are hard to read, let's define a couple of helper functions and a custom operator:
func rmap<S:SequenceType, T>(transform:(S.Generator.Element)->T) -> (S) -> [T] {
return { return map($0, transform) }
}
func rfilter<S:SequenceType>(predicate:(S.Generator.Element)->Bool) -> (S) -> [S.Generator.Element] {
return { sequence in return filter(sequence, predicate) }
}
infix operator <^> { associativity left }
func <^> <S, T>(left:S, right:(S)->T) -> T {
return right(left)
}
And a convenience function to count it's inputs:
func count<T>(array:[T]) -> Int {
return array.count
}
Now we can condense the whole thing as:
numberSeries.values <^> rmap(trimLength(5)) <^> rfilter(containsAll([7, 36])) <^> count

Resources