Allows you to categorize the type of work you’re doing in order to allow GCD to better prioritize the work.
- User Interactive: main thread, animations
- User Initiated: Immediate results
- Utility: Long-running tasks, shouldn’t prevent user progress
- Background: Not user visible
See writing efficient apps talk from 2014 for more info on effectively scheduling background work
Since thermal dissipation is constant (no fans), throughput is managed based on QoS classes in order to control heat.
See power, performance and Diagnostics: Whats new in GCD + XPC WWDC 2014
dispatch_async()
automatically propagates the QoS from the calling thread, though it will translate User Interactive to User Initiated to avoid assigning that priority to non mainthreads.
Captured at time of block submission, translatse user interactive to user initiated. Used if destination queue does not have a QoS and does not lower the QoS (ex dispatch_async back to the main thread)
b = dispatch_block_create_with_qos_class(…)
dispatch_async(q, b)
QoS is captured at block object creation. Can be manually capture the current QoS by DISPATCH_BLOCK_ASSIGN_CURRENT.
DISPATCH_BLOCK_DETACHED
flag tells OS that the block has no relation to current execution flow, won’t capture activity id or QoS scope.
DISPATCH_BLOCK_FORCE_QOS_CLASS
flag tell queue to override QoS for this block
Queue is already running a block lower priority than one is queued. QoS is raised until the higher priority block is run, when you use dispatch_sync() and dispatch_block_wait() or pthread_mutex_lock().
dispach_queue_create(“com.example”, DISPATCH_QUEUE_SERIAL);
will use the QOS of the calling thread, can lead to priority inversion.
dispatch_async(q, ^{
[self performSelector:… withObject:nil afterDelay:1]
})
Won’t get called, because the thread is ephemeral and it doesn’t have a running run loop.
- Bound to a thread
- Gets delegate method callbacks
- AUtorelease pool pots after each iteration
- Can be used reentrantly
- [self performSelector:… withObject:… afterDelay:…]
- Uses ephemeral threads
- Blcok callbacks
- Autorelease pool pops when thread is idle Not guaranteed to happen if queue is busy!
- Will deadlock if used reentrantly
- dispatch_after()
When a thread is waiting (blocked on IO/lock), GCD will spawn additional threads to tackle the next queued work while the first is waiting. Need to be careful about thread explosion, and deadlock.
- Always good advice: use asynchronous APIs, especially for I/O
- Use serial queues where relevant
- Use NSOperationQueues with concurrency limits
- Don’t generate unlimited work
Don’t mix dispatch_async/dispatch_sync when you don’t have to, and especially be careful from the main thread.
// Bad, can experience deadlock/
for (int i = 0; i < 999; i++) {
dispatch_async(q, ^{});
}
dispatch_barrier_sync(q)
// Better
dispatch_apply…
dispach_semaphore can also be used to ensure that only n number of blocks are queued (block submitting code)
Manager thread (_dispatch_manager_thrd), can basically ignore responsible for GCD thread pool
__workq_kernreturn
is an idle gcd thread
_dispach_client_callout
gcd thread calling out to your block
mack_msg_trap
main thread idle
__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__
main thread active