Difference between dispatch_async and dispatch_sync on serial queue?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
On a serial queue, both dispatch_async and dispatch_sync preserve task order because the queue runs one block at a time. The real difference is what happens to the caller. dispatch_async submits work and returns immediately, while dispatch_sync blocks the caller until that work finishes. That difference affects responsiveness, control flow, and deadlock risk.
A Serial Queue Does Not Mean Parallel Work
A serial queue guarantees that submitted blocks execute one after another. Even when you use async, the work is still serialized on that queue. The benefit of async is not parallel execution on the same queue. The benefit is that the caller is free to continue doing other work.
task 1 runs before task 2, but the thread that submitted them does not wait for either block to finish.
dispatch_async Is Non-Blocking Submission
Use dispatch_async when the caller should stay responsive and does not need an immediate result. This is common in UI code, logging pipelines, and background coordination.
The expected output order is before async, then after async, and only later inside async. The queue still processes the submitted block in order, but the caller is not forced to wait.
dispatch_sync Blocks the Caller
dispatch_sync is useful when the current code path must wait until a block completes. That can be appropriate for short, controlled access to a serial queue that protects shared state.
Here the order is before sync, then inside sync, then after sync. The caller does not continue until the block has completed.
Deadlock Is the Critical Risk
The classic mistake is calling sync onto the same serial queue that is already executing the current code. The queue cannot start the new block until the current block finishes, but the current block is waiting for the new block to finish. Execution stops permanently.
The same warning applies to the main queue. Calling DispatchQueue.main.sync from the main thread will freeze the application.
How to Choose Between Them
A good default is to prefer async unless you have a specific need for blocking semantics. If the caller only needs to schedule work and move on, async is simpler and safer. If the caller truly must observe the result before continuing, sync can be appropriate, but only when you are certain there is no path back onto the same active serial queue.
For modern Swift code, it is also worth considering higher-level concurrency features before adding more raw GCD usage. Structured concurrency and actors often express intent more clearly than hand-managed queue coordination.
Common Pitfalls
The biggest mistake is assuming async means parallel execution on a serial queue. Another is using sync on the main thread or from code already running on the same queue, which causes deadlocks or visible UI freezes. Teams also get into trouble when queue ownership is unclear and modules call sync into queues they do not fully understand.
Summary
- Both methods preserve ordering on a serial queue.
- '
dispatch_asyncreturns immediately and lets the caller continue.' - '
dispatch_syncblocks until the submitted block finishes.' - '
dispatch_syncon the same active serial queue can deadlock.' - Prefer
asyncby default unless blocking is a deliberate requirement.

