Difference in Serial vs Concurrent Que && sync vs Async Task

Viewed 556

I am ios development Beginner Studying mutlithreading. Let me Know If I am wrong

I studied that

Serial Queue : 1 thread.

Concurrent Que : multiple thread for each task.

Sync Task : blocks other task till its completion

Async Task : tasks can run parallely..

I write a code for Concurrent Queue sync Tasks VS Serial Queue Async Task as follows :

print("Concurrent Que Sync task ")
        
        let que1 = DispatchQueue(label: "AAA", attributes: .concurrent)
        que1.sync{
            print("Que1 Started")
            for index in 1...3{
                print("1.\(index)")
            }
            print("Que1 Ended")
        }
        let que2 = DispatchQueue(label: "BBB", attributes: .concurrent)
        que2.sync{
            print("Que2 Started")
            for index in 1...2{
                print("2.\(index)")
            }
            print("Que2 Ended")
        }

 print("Serial Que Async task")
        
        let que1 = DispatchQueue(label: "AAA")
        que1.async{
            print("Que1 Started")
            for index in 1...3{
                print("1.\(index)")
            }
            print("Que1 Ended")
        }
        let que2 = DispatchQueue(label: "BBB")
        que2.async{
            print("Que2 Started")
            for index in 1...2{
                print("2.\(index)")
            }
            print("Que2 Ended")
        }

I got output as :

Concurrent Que Sync task 
Que1 Started
1.1
1.2
1.3
Que1 Ended
Que2 Started
2.1
2.2
Que2 Ended
Serial Que Async task
Que1 Started
Que2 Started
2.1
2.2
Que2 Ended
1.1
1.2
1.3
Que1 Ended

I just have Question in case of Concurrent Que sync task : as we have conc queue then we will have 2 threads & we can run only 1 task at a time on both que as it is sync thennnnn why it starting task2 after completion of task1 insteading of running on two seprate therad parallely.

As well as

in case of Serial Que Async task : as we have Serial queue then we will have only 1 threads & we can run multiple task but due to only 1 thread we have to run task2 after task1. Then how it is running 2 task parallely..

PS: Correct me if I missunderstood

2 Answers

The problem is that you are creating 2 concurrent queues and 2 serial queues. Instead what you should be doing is -

  1. Create one concurrent queue and add two tasks to that same concurrent queue.
  2. Create one serial queue and add two tasks to that same serial queue

About SYNC.. Now what sync will do is it will block the calling thread until the task is finished. That is, the control will return once all tasks inside the block will be executed. Suppose your code is like this - in the first line yourQueue.sync { task1 } and the second line is yourQueue.sync { task2 }. Here the second line will not be called unless the first line of code is fully executed, including the task1 inside that {} block. So task1 will completely execute first and task2 will execute after, irrespective whether the queue is serial or concurrent. So essentially concurrentQueue.sync generate the same result as that of a serial queue. But if there is a 3rd line, then that will get control only after the task1 and task2 is finished, since both are synchronous calls.



About ASYNC.. Now if you use async instead of sync in the above example, control will return immediately after the block is hit. That is, if the code is like this - in the first line yourQueue.async { task1 } and the second line is yourQueue.async { task2 }. Now the second line will get called immediately after the first line, without really waiting for the task1 to finish. If this yourQueue is a serial queue, then both task1 and task2 will execute in one thread only and the task2 will wait for the task1 to finish. If yourQueue is a concurrent queue, then both task1 and task2 will execute parallely, since they have separate threads allocated.

I have modified your code little bit. Try changing the que1 and que2 to sync and async and check the results. And notice how and when the “Another task” is executing.

print("Concurrent Que Test")

let que1 = DispatchQueue(label: "AAA", attributes: .concurrent)
que1.sync{
    print("Concurrent Que task1 Started")
    for index in 1...3{
        print("Concurrent - 1.\(index)")
    }
    print("Concurrent Que task1 Ended")
}
que1.sync{
    print("Concurrent Que task2 Started")
    for index in 1...2{
        print("Concurrent - 2.\(index)")
    }
    print("Concurrent Que task2 Ended")
}
print("Another task - 1")

print("\n\nSerial Que Async Test")
        
let que2 = DispatchQueue(label: "AAA")
que2.async{
    print("Serial Que task1 Started")
    for index in 1...3{
        print("Serial - 1.\(index)")
    }
    print("Serial Que task1 Ended")
}
que2.async{
    print("Serial Que task2 Started")
    for index in 1...2{
        print("Serial - 2.\(index)")
    }
    print("Serial Que task2 Ended")
}
print("Another task - 2")

There are two main things to understand in multithreading programming:

1. Serial and concurrent queues

Queues can be "serial", where task (or closures) are performed strictly one after another. Only one task can be performed at a given time. The rest of the tasks wait until the current task is completed.

Queues can be "concurrent", where the system can run tasks concurrently. If the system still has resources, then it takes the next task from the queue and starts it for execution in another thread while the first task is still running.

2. Synchronous and asynchronous execution of tasks

Once the queue is created, the task can be placed on it using two functions: sync - synchronous execution relative to the current queue and async - asynchronous execution relative to the current queue.

The synchronous sync function returns control to the current queue only after the task is complete, thereby blocking the current queue.

The async function, in contrast to the sync function, returns control to the current queue immediately after starting the task execution, without waiting for it to complete. Thus, the async function does not block the execution of code on the current queue.

Thus, the type of queue determines how tasks will be performed in relation to each other, and sync / async functions determine when we get control back to execute the code after calling these functions.

print("Concurrent Que Sync task")

let que1 = DispatchQueue(label: "AAA", attributes: .concurrent)
que1.sync{
    print("Que1 Started")
    for index in 1...3{
        print("1.\(index)")
    }
    print("Que1 Ended")
}

// The code below will be executed only after completion of task 1, since we use a sync call even if the queue is concurrent

let que2 = DispatchQueue(label: "BBB", attributes: .concurrent)
que2.sync{
    print("Que2 Started")
    for index in 1...2{
        print("2.\(index)")
    }
    print("Que2 Ended")
}
print("Serial Que Async task")
        
let que1 = DispatchQueue(label: "AAA")
que1.async{
    print("Que1 Started")
    for index in 1...3{
        print("1.\(index)")
    }
    print("Que1 Ended")
}

// The code below will be executed immediately after task 1 is added to the queue, since we use an async function that returns control immediately after the call

let que2 = DispatchQueue(label: "BBB")
que2.async{
    print("Que2 Started")
    for index in 1...2{
        print("2.\(index)")
    }
    print("Que2 Ended")
}
Related