DispatchQueue vs OperationQueue

Rahul Goel
2 min readJul 4, 2024

--

“Selecting the Right Concurrency Tool for Your Swift Projects”

DispatchQueue and OperationQueue are both powerful concurrency mechanisms in Swift, but they serve different purposes and have distinct characteristics.

DispatchQueue :

Low level lightweight api for basic tasks such as dispatching closures and executing blocks of code.

Provide sync and async execution methods.

No support of task priority inherently.

No direct Support for dependency management between tasks.

let queue = DispatchQueue(label: "com.example.concurrentQueue", attributes: .concurrent)
queue.async {
// Perform some task asynchronously
print("Task 1")
}
print("Task 2")
// Output:
// Task 2
// Task 1 (may appear after Task 2 due to async execution)
let queue = DispatchQueue(label: "com.example.serialQueue")
queue.sync {
// Perform some task synchronously
print("Task 1")
}
print("Task 2")
// Output:
// Task 1
// Task 2

OperationQueue:

High Level api written on using DispatchQueue provide additional features to execute and manage tasks.

Tasks are subclass of Operation or BlockOperation.

Built-in support of task priority inherently.

Built-in Support for dependency management between tasks.

OperationQueue allows you to control how many operations run concurrently (maxConcurrentOperationCount property).

let queue = OperationQueue()
let operation1 = BlockOperation {
// Perform task 1
print("Task 1")
}
let operation2 = BlockOperation {
// Perform task 2
print("Task 2")
}
// Adding dependency
operation2.addDependency(operation1)
queue.addOperations([operation1, operation2], waitUntilFinished: false)
// Output:
// Task 1
// Task 2 (executes after Task 1 completes due to dependency)


class MyOperation: Operation {
override func main() {
// Perform some task
print("Operation Task")
}
}
let queue = OperationQueue()
let operation = MyOperation()
queue.addOperation(operation)
// Output:
// Operation Task


let queue = OperationQueue()
let operation1 = BlockOperation {
// Task 1
print("Task 1")
}
let operation2 = BlockOperation {
// Task 2
print("Task 2")
}
operation1.queuePriority = .high
operation2.queuePriority = .low
queue.addOperations([operation1, operation2], waitUntilFinished: false)
// Output (order can vary based on priority and execution timing):
// Task 1 (high priority)
// Task 2 (low priority)
let queue = OperationQueue()
let operation1 = BlockOperation {
// Task 1
print("Task 1")
}
let operation2 = BlockOperation {
// Task 2
print("Task 2")
}
queue.addOperations([operation1, operation2], waitUntilFinished: false)
// Cancel operation2 after a delay
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
operation2.cancel()
}
// Output:
// Task 1
// (Task 2 might not execute if cancelled before execution)

Operation vs BlockOperation:

// Use when you need to encapsulate complex behavior, manage dependencies, 
// or maintain state within the operation.
class MyOperation: Operation {
override func main() {
// Perform some task
}
}

let operation = MyOperation()
operationQueue.addOperation(operation)
//BlockOperation is subclass of Operation

// Use for simple tasks that can be encapsulated in blocks and do not
// require subclassing or extensive customization.

let blockOperation = BlockOperation {
// Perform some task
}

operationQueue.addOperation(blockOperation)

Follow me Rahul Goel for further updates.

--

--

Rahul Goel

Computer Science Enthusiast | 11+ Year of Software Evolution | @Sharechat, Groupon, Paytm, Myntra https://www.linkedin.com/in/therahulgoel/