4

I have question regarding this issue , According to Apple's documents

Concurrent Concurrent queues (also known as a type of global dispatch queue) execute one or more tasks concurrently, but tasks are still started in the order in which they were added to the queue. The currently executing tasks run on distinct threads that are managed by the dispatch queue. The exact number of tasks executing at any given point is variable and depends on system conditions. In iOS 5 and later, you can create concurrent dispatch queues yourself by specifying DISPATCH_QUEUE_CONCURRENT as the queue type. In addition, there are four predefined global concurrent queues for your application to use. For more information on how to get the global concurrent queues, see Getting the Global Concurrent Dispatch Queues.

And i do a test, using the sample code ,

  dispatch_queue_t concurrentQueue;
    concurrentQueue = dispatch_queue_create("com.gcd.concurrentQueue",
                                                 DISPATCH_QUEUE_CONCURRENT);

    dispatch_async(concurrentQueue, ^{
         NSLog(@"First job ");
    });
    dispatch_async(concurrentQueue, ^{
        NSLog(@"Second job");
    });

    dispatch_async(concurrentQueue, ^{
        NSLog(@"Third job ");
  });

But the results seems not as the order in which they are added, here is the results,

2015-06-03 18:36:38.114 GooglyPuff[58461:1110680] First job 
2015-06-03 18:36:38.114 GooglyPuff[58461:1110682] Third job
2015-06-03 18:36:38.114 GooglyPuff[58461:1110679] Second job

So my question is , shouldn't it be First, Second , Third ?

Any advice is welcome , and thanks for your help.

2 Answers 2

4

"Concurrent" means they run at the same time and no assumptions should be made about where in their progress any of them will be at any given moment and which will finish first. That is the whole meaning and implication of concurrency: between one line of code and the next in one concurrent operation - even during one line of code - anything else from any other concurrent operation might be happening.

So, in answer to your particular question, these tasks may have started in a known order, but that happened very quickly, and after that point their progress is interleaved unpredictably. And your NSLog calls are part of that progress; they do not, and cannot, tell you when the tasks started!

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

6 Comments

according to apple's document , "tasks are still started in the order in which they were added to the queue". So when you say "MAY have started in a known order " what does that mean ?
I think it just means that the results of the when-did-the-NSLog-complete test doesn't strictly answer when they were started. So the 'may' is relative to what we can say from the empirical results. What we can say from the documentation is: yes, they definitely started in the order in which they were enqueued. (obiter: at a guess, it took slightly longer for the slightly longer string to be prepared for display; at least tasks two and three were probably started so close to simultaneously as for the difference to be almost moot)
The key is that the blocks are put into the run state in a known order. But they can immediately come out of the run state. NSLog in particular is a very bad way to test concurrency because it includes a console lock. At a minimum, you should test with printf to get anything even close to reality. In no case, though, could you assume anything about what order the print statements would happen in.
@Tommy , how can i tell or verify whether the task started as the sequence as they are added ?
Isn't that a bit like wanting to verify that the result of a = b + c really is b + c? Unhelpful comments aside, there's no way I can think of since, as Rob says, blocks may be paused at any moment. So whatever you do is definitely going to be unreliable. I'd suggest that something like a global int32_t and use of OSAtomicIncrement32 as the very first thing in your block, then logging the returned number will be as reliable as you can get. But still not entirely reliable.
|
2

The documentation is correct - they will indeed start in the order you added them to the queue. Once in the queue, they will be started one after the other, but on concurrent threads. The order they will finish is dependent on how long the task will take to execute. Here's a thought experiment, imagine your code was like this instead:

    dispatch_async(concurrentQueue, ^{
         JobThatTakes_3_SecToExecute(); // Job 1 (3 seconds to execute)
    });

    dispatch_async(concurrentQueue, ^{
        JobThatTakes_2_SecToExecute(); // Job 2 (2 seconds to execute)
    });

    dispatch_async(concurrentQueue, ^{
        JobThatTakes_1_SecToExecute(); // Job 3 (1 second to execute)
    });

The overhead in and out of the queue should be very small compared to these job lengths, so you would expect them to finish up in about the time that their task takes to execute. In this case they'd finish roughly 1 second apart starting with Job 3, then 2, then 1. The total time the queue would take to complete will be about the length of Job 1, since it takes the longest to execute. This is lovely, since the total time is set primarily by the longest job, not the sum of the jobs. However, you don't have any say in what order they finish, since that's dictated by the task duration.

Change dispatch_async to dispatch_sync in this example and the queue will take about 6 seconds to complete. They'll come out in this order: Job 1, 2, then 3. This will guarantee that your results come out in the order you wanted, but it will take much longer.

So back to the significance of what the docs mean by "tasks are still started in the order in which they were added to the queue" for concurrent queues. This will be noticeable if your job is resource constrained. Say you're putting a big pile of long duration tasks in a concurrent queue on a 2 CPU machine. It is unlikely you'll be able to run a dozen CPU-pegging tasks concurrently here; some will have to wait while others run. The order that you put them into the queue will decide who gets to run next as resources free up. In your example, the tasks are of super short duration and involve console locking (as Rob mentioned), so queue / locking overhead can mess with your expectations.

Another (probably more important) reason the order of execution in concurrent queues matter is when barriers are used. You may need to run some sort of a task every N other tasks, which is where a barrier would come in handy. The fixed order of execution will assure that the barrier executes after N tasks have completed concurrently, provided you put the barrier in the queue in the right spot.

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.