Concurrency with GCD in Swift - 1
Serial Queue:
- Executes only one item at a time irrespective of the number of tasks in the Queue
- Good when there is a necessity to provide controlled access to a queue
func serialQueue() {
let serialQueue = DispatchQueue(label: "test.com")
serialQueue.async {
sleep(10)
print("SERIAL 1")
}
serialQueue.async {
print("SERIAL 2")
}
}
Result:
SERIAL 1
SERIAL 2
Irrespective of the sleep function value SERIAL 2 will be printed only after SERIAL 2 as in serial Queue the processing of the task will be in the order in which tasks gets added to the Queue.
Concurrent Queue:
- Executes multiple tasks (if added) at a time
func customConcurrentQueue() {
let concurrentQueue = DispatchQueue(label: "test.concurrentqueue", attributes: .concurrent)
concurrentQueue.async {
print("CONCURRENT Task 1 started")
print("CONCURRENT Task 1 finished")
}
concurrentQueue.sync {
print("CONCURRENT Task 2 started")
print("CONCURRENT Task 2 finished")
}
}
customConcurrentQueue()
Result of Execution 1:
CONCURRENT Task 1 started
CONCURRENT Task 2 started
CONCURRENT Task 2 finished
CONCURRENT Task 1 finished
Despite Task 1 beginning first, Task 2 which began later was completed. That is concurrency.
Result of Execution 2:
CONCURRENT Task 2 started
CONCURRENT Task 1 started
CONCURRENT Task 2 finished
CONCURRENT Task 1 finished
Synchronous
When a task is executed synchronously, the calling thread is blocked, and only when the execution is completed, the calling thread can continue its execution
Sync in Concurrent Queue
func testSyncInConcurrent() {
DispatchQueue.global().sync {
print("1")
}
print("Post Sync Execution")
DispatchQueue.global().async {
print("2")
}
DispatchQueue.global().async {
print("3")
}
}
testSyncInConcurrent()
Result
1
Post Sync Execution
3
2
Irrespective of any number of executions, 1 will be always printed first in sequence as testSyncInConcurrent() is blocked by the synchronous block of execution.
Sync in Serial Queue
func testSyncinSerial() {
let serialQueue = DispatchQueue(label: "test.com")
serialQueue.sync {
print("1")
}
print("Post Sync Execution")
serialQueue.async {
print("2")
}
serialQueue.async {
print("3")
}
}
testSyncinSerial()
Result:
1
Post-Sync Execution
2
3
Asynchronous:
When a task is executed asynchronously, the calling thread is not blocked and can continue to execute other tasks it has been enqueued with.
Let us execute all async tasks in a serial Queue. Since serial queue does always execute the tasks one by one, even though the tasks are asynchronous in nature, they get executed one by one.
func testAsyncInSerial() {
let serialQueue = DispatchQueue(label: "test.com")
serialQueue.async {
print("1")
sleep(10)
}
print("Post ASync Execution")
serialQueue.async {
print("2")
}
serialQueue.async {
print("3")
}
}
Result:
1
Post ASync Execution
2
3
Let us execute multiple async tasks in a concurrent queue. Unlike the last time in serial queue, the order of execution does not follow as the tasks are added to the queue. With each new execution of the code the order of tasks executed has changed.
func testAsyncInConcurrent() {
let concurrent = DispatchQueue.global()
concurrent.async {
print("BEGIN 1")
sleep(10)
print("END 1")
}
print("Post ASync Execution")
concurrent.async {
print("BEGIN 2")
print("END 2")
}
concurrent.async {
print("BEGIN 3")
print("END 3")
}
}
testAsyncInConcurrent()
Result of Execution 1
BEGIN 1
Post ASync Execution
BEGIN 2
END 2
BEGIN 3
END 3
END 1
Result of Execution 2:
BEGIN 1
Post ASync Execution
BEGIN 3
END 3
BEGIN 2
END 2
END 1