3

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.

9
  • If I where to guess each async call is awaiting the work to be finished. The main difference between your code and the example is that code is still being execused in the async while the loop is being executed in the main thread. Commented Sep 25, 2017 at 17:37
  • They are also doing it on two seperate queues while you're doing it on one. Create a reference to the same object and trying doing asyn on currentQueue1 Commented Sep 25, 2017 at 17:40
  • 2
    It could be just a timing issue - there's no guaranty how long each operation will execute before the other kicks in. To test this, put a random sleep call in the loops to see how the output changes. Something like usleep( arc4random() % 100000 ) Commented Sep 25, 2017 at 17:44
  • @SamMarion how is it possible? Do “for” loops run in the main thread? I didnt get it. And I have done what is exactly in the tutorial. Commented Sep 25, 2017 at 18:06
  • 1
    @GMHSJ The for loops can interrupt each other while they are executing, but that doesn't mean that they WILL interrupt each other. If the loop only takes a few milliseconds, it's entirely possible for it to complete before the other loop even starts. What's even more fun is that you can run the code 1000 times in a row getting one result and then on the 1001st run you can get a different one. Makes debugging challenging. Commented Sep 25, 2017 at 22:45

2 Answers 2

4

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Will try your suggestions and check. I understood what you are saying but i dont think it is something happening because of the device i use, in my situation. Im saying that to get this out put I dont need concurrent queues, simply i can use a global queue in which these two for loops can take place. Thanks for helping btw friend.
After I put the stuff inside for loops it worked as I expected. yes It is a timming thing. Thanks @Rob
1

May be you could try using semaphore.

    let semaphore1 = DispatchSemaphore(value: 1)
    let semaphore2 = DispatchSemaphore(value: 0)
    concurrentQueue.async {
    for i in 0 ..< 10{
    semaphore1.wait()
    print(i)
    semaphore2.signal()
    }
    }

    concurrentQueue.async {

    for i in (0 ..< 10).reversed(){
    semaphore2.wait()
    print(i)
    semaphore1.signal()
    }
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.