Home > Software engineering >  Swift Concurrency
Swift Concurrency

Time:11-30

I am looking to implement concurrency inside part of my app in order to speed up processing. The input array can be a large array, that I need to check multiple things related to it. This would be some sample code.

private func testFunc(inputArray: [Int]) {
        let dataIterationArray = Array(Set(inputArray))
        let syncQueue = DispatchQueue(label: "syncQueue")
        DispatchQueue.concurrentPerform(iterations: dataIterationArray.count) { index in
            
            
            //I want to do these three for loops in parallel with each other
            for i in 1...10{
                print ("i \(i)")
            }
            
            for j in 11...20{
                print ("j \(j)")
            }
            
            for k in 21...30{
                print ("k \(k)")
            }
            
            
            //And then wait here until all of the loops are done before processing
        }
    }

CodePudding user response:

I will explain it here, since comment is too small, but will delete later if it doesn't answer the question.

Instead of looping over iterations: dataIterationArray.count, have number of iterations based on number of desired parallel streams of work, not based on array size. For example as you mentioned you want to have 3 streams of work, then you should have 3 iterations, each iteration processing independent part of work:

DispatchQueue.concurrentPerform(iterations: 3) { iteration in 
    switch iteration {
    case 0:
        for i in 1...10{
            print ("i \(i)")
        }
    case 1:
        for j in 11...20{
            print ("j \(j)")
        }
    case 2:        
        for k in 21...30{
            print ("k \(k)")
        }
    }
}

And the "And then wait here until all of the loops are done before processing" will happen automatically, this is what concurrentPerform guarantees.

CodePudding user response:

The basic idea is to “stride” through the values. So calculate how many “iterations” are needed and calculate the “start” and “end” index for each iteration:

private func testFunc(inputArray: [Int]) {
    DispatchQueue.global().async {
        let array = Array(Set(inputArray))
        let syncQueue = DispatchQueue(label: "syncQueue")

        // calculate how many iterations will be needed

        let count = array.count
        let stride = 10
        let (quotient, remainder) = count.quotientAndRemainder(dividingBy: stride)
        let iterations = remainder == 0 ? quotient : quotient   1

        // now iterate

        DispatchQueue.concurrentPerform(iterations: iterations) { iteration in

            // calculate the `start` and `end` indices

            let start = stride * iteration
            let end = min(start   stride, count)

            // now loop through that range

            for index in start ..< end {
                let value = array[index]
                print("iteration =", iteration, "index =", index, "value =", value)
            }
        }

        // you won't get here until they're all done; obviously, if you 
        // want to now update your UI or model, you may want to dispatch
        // back to the main queue, e.g.,
        //
        // DispatchQueue.main.async { 
        //     ...
        // }
    }
}

Note, if something is so slow that it merits concurrentPerform, you probably want to dispatch the whole thing to a background queue, too. Hence the DispatchQueue.global().async {…}. You would probably want to add a completion handler to this method, now that it runs asynchronously, but I will leave that to the reader.

  • Related