Search code examples
iosswift3grand-central-dispatchconcurrent-queue

Concurrent Queue Issue - iOS/Swift


In my program I need two tasks to run simultaneously in the background. To do that i have used concurrent queues as below,

let concurrentQueue = DispatchQueue(label: "concurrentQueue", qos: .utility, attributes: .concurrent)

concurrentQueue.async {
    for i in 0 ..< 10{
        print(i)
    }
}

concurrentQueue.async {
    for i in (0 ..< 10).reversed(){
        print(i)
    }
}

Here I need the output like this,

0
9
1
8
2
7
3
6
4
5
5
4
6
3
7
2
8
1
9
0

But what I get is,

enter image description here

I referred below tutorial in order to have some basic knowledge about Concurrent Queues in Swift 3
https://www.appcoda.com/grand-central-dispatch/

Can someone tell me what is wrong with my code? or else is it the result I should get? Is there any other ways to get my thing done? Any help would be highly appreciated.


Solution

  • There is nothing wrong with your code sample. That is the correct syntax for submitting two tasks to a concurrent queue.

    The problem is the expectation that you'd necessarily see them run concurrently. There are two issues that could affect this:

    1. The first dispatched task can run so quickly that it just happens to finish before the second task gets going. If you slow them down a bit, you'll see your concurrent behavior:

      let concurrentQueue = DispatchQueue(label: Bundle.main.bundleIdentifier! + ".concurrentQueue", qos: .utility, attributes: .concurrent)
      
      concurrentQueue.async {
          for i in 0 ..< 10 {
              print("forward: ", i)
              Thread.sleep(forTimeInterval: 0.1)
          }
      }
      
      concurrentQueue.async {
          for i in (0 ..< 10).reversed() {
              print("reversed:", i)
              Thread.sleep(forTimeInterval: 0.1)
          }
      }
      

      You'd never sleep in production code, but for pedagogical purposes, it can better illustrate the issue.

      You can also omit the sleep calls, and just increase the numbers dramatically (e.g. 1_000 or 10_000), and you might start to see concurrent processing taking place.

    2. Your device could be resource constrained, preventing it from running the code concurrently. Devices have a limited number of CPU cores to run concurrent tasks. Just because you submitted the tasks to concurrent queue, it doesn't mean the device is capable of running the two tasks at the same time. It depends upon the hardware and what else is running on that device.

      By the way, note that you might see different behavior on the simulator (which is using your Mac's CPU, which could be running many other tasks) than on a device. You might want to make sure to test this behavior on an actual device, if you're not already.


    Also note that you say you "need" the output to alternate print statements between the two queues. While the screen snapshots from your tutorial suggest that this should be expected, you have absolutely no assurances that this will be the case.

    If you really need them to alternate back and forth, you have to add some mechanism to coordinate them. You can use semaphores (which I'm reluctant to suggest simply because they're such a common source of problems, especially for new developers) or operation queues with dependencies.