GCD vs custom queue - ios

I was wondering what is the difference in performance between these two.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
// perform complex operation
// dispatch back to main thread to update UI
});
dispatch_async(_myCustomConcurrentQueue, ^{
// perform complex operation
// dispatch back to main thread to update UI
});
My assumption is the GCD is used across the os and other applications, and it will need to perform very quick background tasks, and be finished quick. And custom queues that are created are separate from GCD and they can run a different task, and will be added back to the pool once they are released. And so my assumption is that my customQueue performs better than GCD for a complex operation.
What are your thoughts? Which performs better? Are they the same?

While the high-priority global queue might theoretically be faster (since you don't have to create the queue, slightly different thread priority), the difference between that and your own custom concurrent queue is unlikely to be observable. There are two reasons, though, that you might want to use your own custom queues:
Certain features, notably dispatch barriers, are unavailable in global queues, so if you need those features, you'll want to use custom queue.
Debugging your app, it can also be useful to use your own queues with meaningful names, so that you can more easily identify the individual threads in the debugger.
But there are no material performance reasons to choose high priority global concurrent queue vs a custom concurrent queue.

Well, you don't say how _myCustomConcurrentQueue was created (it could be a serial queue or a concurrent queue), but assuming that it's a concurrent queue then it will have potentially a different priority than the global concurrent queues, both in terms of how GCD dispatches blocks or functions from its internal "queue of queues" blocklist and in the actual thread priority of the thread(s) created to do the work!
Please read the dispatch_queue_create(3) man page and pay specific attention to the "GLOBAL CONCURRENT QUEUES" section. It contains some very informative verbiage on this exact topic (too much to cut-and-paste here).

I'm pretty sure that if you create your own queue, it ultimately gets added to the GCD behind the scenes. I guess it's more of a preference thing.

Related

Are threads shared between different Dispatch queues?

Can a single thread be used in different dispatch queues?
I'm developing an app where i want to get a value depending on the thread where the code is running. For that i change the name of the thread when the block starts in a custom queue.
For example, if I add a block to mi custom queue, and i change the name of that thread to "SyncThread". Does a block called in a default system queue will be executed in that "SyncThread"?
Can a single thread be used in different dispatch queues?
Yes, and this is common. (The concept of "different dispatch queues" is itself problematic, since queues can, and do, target other queues. Seemingly simple questions like "what is the current queue" are not well defined.)
I'm developing an app where i want to get a value depending on the thread where the code is running. For that i change the name of the thread when the block starts in a custom queue.
What you likely want for this is queue contextual data rather than thread-specific data (usually called thread-local storage). See DispatchQueue.setSpecific(key:value:).
You use the terms thread and queue interchangeably but they aren't interchangeable; they're two distinct things. Apple doesn't want developers threading anymore, they want developers queueing their tasks. The queueing is handled by GCD which does all the threading behind the scenes. This means that two queues can certainly run on the same thread. And while all tasks within a queue run on distinct threads, not every task is guaranteed to run on the same thread, so keep that in mind. Therefore, I would take the advice given here to focus instead on queue context, not thread context.

GCD: does thread only has two types? main thread and background thread

Context:
From my understanding, the Main DispatchQueue only dispatch tasks on Main Thread which is for UI mostly.
However the Main Thread can also be used by non-main DispatchQueues.
Apple has QOS to priorities the tasks:
User Interactive: Work that happens on the main thread, such as animations or drawing operations.
User Initiated: Work that the user kicks off and should yield immediate results. This work must be completed for the user to continue.
Utility: Work that may take a bit and doesn’t need to finish right away. Analogous to progress bars and importing data.
Background: This work isn’t visible to the user. Backups, syncs, indexing, etc.
My Question Is:
0, as title described, does thread only contain 2 types, which are Main Thread and Background Thread?
1, does Background Thread mean that all the tasks executed won't block the UI ?
2, Since it mentions that the User Interactive is the priority that the task will be executed on the main thread to avoid UI lags, does it mean all other types: User Initiated, Utility, Background will make sure to have Background Thread that does not block UI?
3, From the link, How to create dispatch queue in Swift 3.
It mentions a couple of different ways to create a Dispatch Queue, some are concurrent, some are serial. It also mentions that by assigning QOS with default or background, it guarantees that the Queue accesses to background threads. But nothing like this mentioned in the Serial and Concurrent. I wonder are those correct?
You ask:
does thread only contain 2 types, which are Main Thread and Background Thread?
I’m not sure if I’d describe them as different “types”, but from the application developer’s perspective, yes, there is the “main” thread, dedicated to the UI, the main run loop, etc., and there are all other threads, which are, in contrast and by definition, “background” threads.
We always want to be careful as to what we run the main queue (i.e. don’t run anything on it that could block that thread and effectively block the UI). In practice, we want to avoid doing anything on the main queue that could block it for more than a few milliseconds, at most.
does Background Thread mean that all the tasks executed won't block the UI?
Effectively, yes. But we’re dealing with limited resources on our devices and therefore the developers must be judicious. For example, for our background tasks, we want to use a QoS that is commensurate for what that queue is doing. Or if parallelizing some task, one should be careful about constraining the degree of concurrency. But if one is judicious about the use of system resources, and keep blocking tasks off the main queue, then that can ensure a responsive UI.
Bottom line, yes, if you have some code that would block the thread on which its run (e.g. it’s computationally expensive, it has blocking calls like semaphores or dispatch group wait, etc.), you would generally run that on a background thread to avoid blocking the main queue.
Since it mentions that the User Interactive is the priority that the task will be executed on the main thread to avoid UI lags, does it mean all other types: User Initiated, Utility, Background will make sure to have Background Thread that does not block UI?
These are just “quality of service” levels, which are just relative priorities for queues. It’s not a question of “block the UI” or “not”, but rather just a matter of how GCD prioritizes and allocates resources.
From the link, How to create dispatch queue in Swift 3. It mentions a couple of different ways to create a Dispatch Queue, some are concurrent, some are serial...
Yes
... It also mentions that by assigning QOS with default or background, it guarantees that the Queue accesses to background threads...
This doesn’t quite make sense. Perhaps you can share the specific excerpt from the docs and we can help you interpret what they were trying to say.
... But nothing like this mentioned in the Serial and Concurrent. I wonder are those correct?
The QoS is just a question of priority and resources for a given queue. Serial vs concurrent is just a question of whether a queue is limited to a single thread at a time, or whether it can avail itself of multiple threads when needed and available.

With NSOperationQueue, how do you add to a background queue instead of main, and how does controlling amount of operations work?

I'm loving NSOperationQueue but I'm having some issues understanding some portions of it.
In the second issue of objc.io they go over NSOperationQueue and mention that it has two kinds of queues, the main queue which runs on the main thread, and the background queues. They mention you can access the main queue with [NSOperation mainQueue] and then add manipulate it.
You normally would not want to do this, correct? If it's running on the main thread, will it not block the main thread for other tasks? Wouldn't it not run concurrently with other tasks?
It also mentions you can add to the background queues (which I understand would be better?) by creating instances of NSOperation (subclasses potentially).
Do I save a reference to the NSOperationQueue that I create for operations in order to have for creating more operations? I assume there's no singleton for background queues like there is for mainQueue, so how do I manage adding tasks to background queues?
It also mentions you can control the amount of operations running concurrently with the maxConcurrentOperationCount property.
I know normally you set it to NSOperationQueueDefaultMaxConcurrentOperationCount, but if I set it to a specific number manually, does it correspond to the maximum number of threads that can be run at once? For example if the processor on the iPhone can run 4 threads at once and I set that property to 8, what happens?
You ask:
You normally would not want [to add operations to the mainQueue], correct? If it's running on the main thread, will it not block the main thread for other tasks? Wouldn't it not run concurrently with other tasks?
Yes, you would never want to add anything slow to the main queue. But that doesn't mean that you don't use the main queue. For some operations (e.g. UI updates) it's critical.
The typical pattern is to create a operation queue for tasks that you want to run in the background, but if you subsequently need to do something that needs to run on the main queue (e.g. UI updates, updating the model, etc.), you would go ahead and do that, for example:
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperationWithBlock:^{
// do some time consuming stuff in the background
// when done, you might update the UI in the main queue
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
// update the UI here
}];
];
You ask:
Do I save a reference to the NSOperationQueue that I create for operations in order to have for creating more operations? I assume there's no singleton for background queues like there is for mainQueue, so how do I manage adding tasks to background queues?
Yes, if you want to add more operations to that same queue later, yes, you want to maintain a reference to that queue. You can do this by adding it to the app delegate, some central view controller, or a singleton.
But yes, there's no built-in singleton for background queues (because you can, conceivably have different queues for different operations, e.g. one for network operations, one for image processing, etc.). But you can write your own singleton for each queue of each type, if you want.
You also ask:
I know normally you set it to NSOperationQueueDefaultMaxConcurrentOperationCount, but if I set it to a specific number manually, does it correspond to the maximum number of threads that can be run at once? For example if the processor on the iPhone can run 4 threads at once and I set that property to 8, what happens?
One should set maxConcurrentOperationCount to be whatever you think is appropriate for the type of queue. For network operation queue, you generally wouldn't exceed 4, but for other types of queues, you might easily have more. I believe that there is a maximum of 64 worker threads (which concurrent queues avail themselves as they need threads).
If you attempt to use more than that, the app won't start your operation until a worker thread becomes available. Apple advises, though, that one refrain from using up all of the worker threads. So use a reasonable number appropriate for your queue's function. Frankly, one of the advantages of operation queues over dispatch queues is that you can constrain the maximum number of worker threads that will be used at any given time to better manage the device's limited resources.
References
WWDC 2012 video Asynchronous Design Patterns with Blocks, GCD, and XPC is an excellent primer on some GCD patterns and touches upon the "too many threads" question.
The Building Concurrent User Interfaces on iOS video walks through some practical implications of building concurrent iOS apps.
The About Threaded Programming section of the Threading Programming Guide touches upon the relationship between cores and threads.
The Concurrency and Application Design section of the Concurrency Programming Guide is an articulate discussion of the relationships between threads and operation/dispatch queues.
Generally you don't want to use the main queue. Any operation there will run on the main thread.
When you create an operation queue, create it for a purpose. Like it will be used for all server requests. So you can control how many concurrent requests are in progress. So don't add algorithmic processing operations to this queue because they have a different purpose. Keep a reference to the queue so you can add operations in future (and pause / cancel operations).
There is no 'normal' setting for maxConcurrentOperationCount - it should be set based on the purpose.
If you set it to 8 then the queue will run up to 8 at the same time. This may not be the most efficient option. Always keep the purpose of the queue in mind.
First of all, you will have to keep in mind that you always separate the main thread with the background thread. Only the operations which involve updating the UI must be performed in the main thread and rest of the operations must be performed in the Background thread. e.g if you are dealing with the multiple downloads, then you have to take care of all the network based operations in the background queue, and you will have to perform the UI update in the main queue.
//e.g for updating UI in main thread.
[self performSelectorOnMainThread:#selector(updateUI) withObject:nil waitUntilDone:YES];
Also when you use set maxConcurrentOperationCount property as NSOperationQueueDefaultMaxConcurrentOperationCount, it means the operationQueue takes the number of concurrent operations depending on the system environment.
Useful Links:
http://mobile.tutsplus.com/tutorials/iphone/nsoperationqueue/
http://www.raywenderlich.com/19788/how-to-use-nsoperations-and-nsoperationqueues
http://www.cimgf.com/2008/02/16/cocoa-tutorial-nsoperation-and-nsoperationqueue/

If I want a task to run in the background, how does the "dispatch_get_global_queue" queue work?

When selecting which queue to run dispatch_async on, dispatch_get_global_queue is mentioned a lot. Is this one special background queue that delegates tasks to a certain thread? Is it almost a singleton?
So if I use that queue always for my dispatch_async calls, will that queue get full and have to wait for things to finish before another one can start, or can it assign other tasks to different threads?
I guess I'm a little confused because when I'm choosing the queue for an NSOperation, I can choose the queue for the main thread with [NSOperationQueue mainQueue], which seems synonymous to dispatch_get_main_queue but I was under the impression background queues for NSOperation had to be individually made instances of NSOperationQueue, yet GCD has a singleton for a background queue? (dispatch_get_global_queue)
Furthermore - silly question but wanted to make sure - if I put a task in a queue, the queue is assigned to one thread, right? If the task is big enough it won't split it up over multiple threads, will it?
When selecting which queue to run dispatch_async on,
dispatch_get_global_queue is mentioned a lot. Is this one special
background queue that delegates tasks to a certain thread?
A certain thread? No. dispatch_get_global_queue retrieves for you a global queue of the requested relative priority. All queues returned by dispatch_get_global_queue are concurrent, and may, at the system's discretion, dispatch work to many different threads. The mechanics of this are an implementation detail that is opaque to you as a consumer of the API.
In practice, and at the risk of oversimplifying it, there is one global queue for each priority level, and at the time of this writing, based on my experience, each of those will at any given time be dispatching work to between 0 and 64 threads.
Is it almost a singleton?
Strictly no, but you can think of them as singletons where there is one singleton per priority level.
So if I use that queue always for my dispatch_async calls, will that
queue get full and have to wait for things to finish before another
one can start, or can it assign other tasks to different threads?
It can get full. Practically speaking, if you are saturating one of the global concurrent queues (i.e. more than 64 background tasks of the same priority in flight at the same time), you probably have a bad design. (See this answer for more details on queue width limits)
I guess I'm a little confused because when I'm choosing the queue for
an NSOperation, I can choose the queue for the main thread with
[NSOperationQueue mainQueue], which seems synonymous to
dispatch_get_main_queue
They are not strictly synonymous. Although NSOperationQueue uses GCD under the hood, there are some important differences. For instance, in a single pass of the main run loop, only one operation enqueued to +[NSOperationQueue mainQueue] will be executed, whereas more than one block submitted to dispatch_get_main_queue might be executed on a single run loop pass. This probably doesn't matter to you, but they are not, strictly speaking, the same thing.
but I was under the impression background
queues for NSOperation had to be individually made instances of
NSOperationQueue, yet GCD has a singleton for a background queue?
(dispatch_get_global_queue)
In short, yes. It sounds like you're conflating GCD and NSOperationQueue. NSOperationQueue is not just a "trivial wrapper" around GCD, it's its own thing. The fact that it's implemented on top of GCD should not really matter to you. NSOperationQueue is a task queue, with an explicitly settable width, that you can create instances of "at will." You can make as many of them as you like. At some point, all instances of NSOperationQueue are, when executing NSOperations, pulling resources from the same pool of system resources as the rest of your process, including GCD, so yes, there are some interactions there, but they are opaque to you.
Furthermore - silly question but wanted to make sure - if I put a task
in a queue, the queue is assigned to one thread, right? If the task is
big enough it won't split it up over multiple threads, will it?
A single task can only ever be executed on a single thread. There's not some magical way that the system would have to "split" a monolithic task into subtasks. That's your job. With regard to your specific wording, the queue isn't "assigned to one thread", the task is. The next task from the queue to be executed might be executed on a completely different thread.

What is the difference between dispatch_get_global_queue and dispatch_queue_create?

I'm writing a moderately complex iOS program that needs to have multiple threads for some of its longer operations (parsing, connections to the network...etc). However, I'm confused as to what the difference is between dispatch_get_global_queue and dispatch_queue_create.
Which one should I use and could you give me a simple explanation of what the difference is in general? Thanks.
As the documentation describes, a global queue is good for concurrent tasks (i.e. you're going to dispatch various tasks asynchronously and you're perfectly happy if they run concurrently) and if you don't want to encounter the theoretical overhead of creating and destroying your own queue.
The creating of your own queue is very useful if you need a serial queue (i.e. you need the dispatched blocks to be executed one at a time). This can be useful in many scenarios, such as when each task is dependent upon the preceding one or when coordinating interaction with some shared resource from multiple threads.
Less common, but you will also want to create your own queue if you need to use barriers in conjunction with a concurrent queue. In that scenario, create a concurrent queue (i.e. dispatch_queue_create with the DISPATCH_QUEUE_CONCURRENT option) and use the barriers in conjunction with that queue. You should never use barriers on global queues.
My general counsel is if you need a serial queue (or need to use barriers), then create a queue. If you don't, go ahead and use the global queue and bypass the overhead of creating your own.
If you want a concurrent queue, but want to control how many operations can run concurrently, you can also consider using NSOperationQueue which has a maxConcurrentOperationCount property. This can be useful when doing network operations and you don't want too many concurrent requests being submitted to your server.
Just posted in a different answer, but here is something I wrote quite a while back:
The best way to conceptualize queues is to first realize that at the very low-level, there are only two types of queues: serial and concurrent.
Serial queues are monogamous, but uncommitted. If you give a bunch of tasks to each serial queue, it will run them one at a time, using only one thread at a time. The uncommitted aspect is that serial queues may switch to a different thread between tasks. Serial queues always wait for a task to finish before going to the next one. Thus tasks are completed in FIFO order. You can make as many serial queues as you need with dispatch_queue_create.
The main queue is a special serial queue. Unlike other serial queues, which are uncommitted, in that they are "dating" many threads but only one at time, the main queue is "married" to the main thread and all tasks are performed on it. Jobs on the main queue need to behave nicely with the runloop so that small operations don't block the UI and other important bits. Like all serial queues, tasks are completed in FIFO order.
If serial queues are monogamous, then concurrent queues are promiscuous. They will submit tasks to any available thread or even make new threads depending on system load. They may perform multiple tasks simultaneously on different threads. It's important that tasks submitted to the global queue are thread-safe and minimize side-effects. Tasks are submitted for execution in FIFO order, but order of completion is not guaranteed. As of this writing, there are only three concurrent queues and you can't make them, you can only fetch them with dispatch_get_global_queue.
edit: blog post expanding on this answer: http://amattn.com/p/grand_central_dispatch_gcd_summary_syntax_best_practices.html
One returns the existing global queue, the other creates a new one. Instead of using GCD, I would consider using NSOperation and operation queue. You can find more information about it in this guide. Typically, of you want the operations to execute concurrently, you want to create your own queue and put your operations in it.

Resources