What is the Concurrency how many ways to achieve Concurrency/Multithreading iOS getting started with Grand Central Dispatch (GCD) Swift 5.2 ?







We are going to take a look at threading and Grand Central Dispatch in Swift, we will explore what threads and queues are as well as the Grand Central Dispatch or GCD APIs is to manage your queues in the process, it will also touch on synchronous vs. asynchronous. Finish with an overview of the code and dispatch groups but this is something you want to learn in this tutorial.



    What is Concurrency/Multithreading?:

    We can optimize the performance of an app in numerous ways, concurrency is one among them.
    You will need to know concurrency to make your app more responsive and fast. 
    Concurrency is a condition in a program where more than one task is happening at the same time then it’s called concurrency.iOS 4 supports multiple tasks to execute at the same time. We will run multiple tasks at an equivalent time by adding some code. So you'll run tasks within the background (like downloading or processing data) while you retain your interface responsively.


    In iOS, we can achieve concurrency in two ways. 
    • Using Grand Central Dispatch(GCD)
    • Using Operations and OperationQueues 

    GCD (Grand Central Dispatch):


    Grand Central Dispatch (GCD) is a low-level API for managing concurrent operations either asynchronously or synchronously. GCD is often wont to manage heavy tasks to the background in order that we will improve our app’s responsiveness.

    The Grand Central Dispatch was first introduced in iOS 4, and it 
    is the easiest method to realize multitasking in iOS. We add tasks to dispatch queues which successively gets executed on multiple threads simultaneously. 

    GCD has lots of benefits like
    • It improves application performance and responsiveness.
    • The app will become more smooth.
    • Execute multiple tasks at a time or one by one as per your requirements.

    Thread:

    Threading is an important concept in iOS. Thread in computer science is a way to run tasks simultaneously. Some languages support multithreading some not. The concept is pretty simple. This is what happens inside the processor. Consider launching an app in your iPhone. 

    every iOS application has a main thread that is there to display your user interface and listen for events. complex computations may slow down the main thread and freeze the app and here's where multi-threading comes into play we must move all of the heavy liftings to a background thread and then move the result back onto the main thread. these threads might be executing their code simultaneously with a multi-core iOS device but they might also just be switching back and forth really quickly and some threads get a higher priority.

    Main Thread:

    In iOS, there is a concept of the Main Thread or UI Thread. That thread becomes user interaction as a user button click.
    The main thread is responsible for keeping the UI running smoothly and responding to user input. It can only execute one task at a time.
    If you begin a process on the Main Thread which is extremely long, like a complex calculation or loading process, this process will attempt to complete. While it's completing, though, your UI and responsiveness to user input will hang.
    -Keep the UI thread free, to keep your app responsive 

    Background Thread:

    All iOS apps use the main thread to handle UI operations. Calling long-running operations from this main thread can lead freezes and unresponsiveness. for instance, if your app makes a network request from the most thread, your app's UI is frozen until it receives the network response. you'll create additional background threads to handle long-running operations while the most thread continues to handle UI updates.

    Therefore, time-consuming processes should be done in a separate thread say a “Background thread” to free up the main UI thread so that the app remains responsive. If heavy operations like network calls, database access, and image downloading are performed on a background thread.


    Queues: 

    Queues are just a bunch of code blocks lined up or queued up waiting for a thread to execute them. you don't need to worry about threads in Swift only Queues the system takes care of providing and allocating threads to execute the code of the Queue.

    Queues are data structures that manage objects within the order of First-in, First-out (FIFO). Queues are almost like the lines at the window of the cinema. Queues in computer science are similar because the first object added to the queue in the first object to removed from the queue.

    Dispatch Queues:

    An object that manages the execution of tasks serially or concurrently on your app's main thread or on a background thread.

    Dispatch queues are a simple way to perform tasks asynchronously and concurrently in your application. A task is just some work that your application must perform. for instanceyou'll define a task to perform some calculations, create or modify a knowledge structure, process some data read from a file, or any number of things. You define tasks by placing the corresponding code inside either a function or a block object and adding it to a dispatch queue.


    A dispatch queue is an object-like structure that manages the tasks you submit to it. All dispatch queues are first-in, first-out data structures. Thus, the tasks you add to a queue are always started in the same order that they were added. 
    Dispatch queues are thread-safe which suggests that you simply can access them from multiple threads simultaneously. Dispatch Queue isn't Thread. Dispatch Queues, A dispatch queue is responsible for executing a task in the first-in, first-out order.

    Different Types of Dispatch Queues:

    1. Main Queue 
    2. Serial queues 
    3. Concurrent queues

    Main Queue:

    It is an object that manages the execution of tasks serially or concurrently on your app's main thread or on a background thread.

    (UIKit and AppKit) aren't thread-safe. Any update on UI should be performed in the main thread. Even it's true for NotifcationCenter, suppose using post notification your application goes to update UI, make sure posting notification is additionally happening in the main thread.

    How about the main thread?:

    The main dispatch queue is a globally available serial queue executing tasks on the application’s main thread. As the main thread is used for UI updates it’s important to be conscious when executing tasks on this queue. Therefore, it’s valuable to use the earlier described dispatch APIs to perform tasks on a different thread.

    You can start doing the heavy lifting on a background queue and dispatch back to the main queue when you’re done.

    let concurrentQueue = DispatchQueue(label: "appcodezip.concurrent.queue", attributes: .concurrent)
            
            concurrentQueue.async {
                // Perform the data request and JSON decoding on the background queue.
                fetchData()
                
                DispatchQueue.main.async {
                    /// Access and reload the UI back on the main queue.
                    tableView.reloadData()
                }
            }
    

    Serial Queues:

    Serial queues execute one task at a time and within the order during which they're added to the queue. The currently executing task runs on a distinct thread that's managed by the dispatch queue. 

    Serial queues guarantee that just one task runs at any given time. GCD controls the execution timing. You won’t know the quantity of your time between one task ending and therefore the next one beginning. Serial Dispatch Queue A serial dispatch queue runs tasks one at a time.


    Concurrent queues:

    Concurrent queues allow multiple tasks to run at an equivalent time. The queue guarantees tasks start within the order you add them. Tasks can finish in any order and you've got no knowledge of the time it'll deem subsequent task to start out , nor the number of tasks that are running at any given time.
    Concurrent Dispatch Queue A concurrent dispatch queue runs as many tasks as it can without waiting for the started tasks to finish.



    Serial vs Concurrent Dispatch Queues with an example:


    Example with Serial Queue-

        func serialQueues () {
            let serialQueue = DispatchQueue(label: "appcodezip.com") //default queue type is a serial queue
            let startDate = Date ()
            for i in 0...4 {
                serialQueue.async {      //run tasks on a background thread
                    sleep(2)        //do some task as webservice or database
                    let timeTaken = Date().timeIntervalSince(startDate)
                    print("serial Queue task \(i) done! total time taken: \(timeTaken)")
                }
            }
        }
    
    Program Execution-
    serial Queue task 0 done! total time taken: 2.0022469758987427
    serial Queue task 1 done! total time taken: 4.005535006523132
    serial Queue task 2 done! total time taken: 6.005913019180298
    serial Queue task 3 done! total time taken: 8.007167935371399
    serial Queue task 4 done! total time taken: 10.011394023895264
    
    Example with concurrent Queue -
    func concurrentQueues () {
            let concurrentQueue = DispatchQueue(label: "appcodezip.com", attributes: .concurrent)
            let startDate = Date ()
            for i in 0...4 {
                concurrentQueue.async {
                    sleep(2)            //do some task as webservice or database
                    let timeTaken = Date().timeIntervalSince(startDate)
                    print("concurrent Queue task \(i) done! total time taken: \(timeTaken)")
                }
            }
        }
    
    Program Execution-
    concurrent Queue task 2 done! total time taken: 2.001850962638855
    concurrent Queue task 3 done! total time taken: 2.0018709897994995
    concurrent Queue task 1 done! total time taken: 2.0017420053482056
    concurrent Queue task 4 done! total time taken: 2.0018869638442993
    concurrent Queue task 0 done! total time taken: 2.0017420053482056
    

    As we will see from the examples above, a serial queue will complete each task within the order they're submitted to the queue. Each task will await the previous task to end before executing. As for the concurrent queue, each task doesn't serve the others within the queue and executes as soon as possible; the advantage is that each task on the queue will run at an equivalent time on separate threads, making a concurrent queue take less time than a serial queue. If the order of execution of tasks isn't important, always use a concurrent queue for the simplest efficiency.


    Concurrent queue often known as global dispatch queues can execute tasks simultaneously as a developer you can determine which of the background Queues get more priority over other ones and you do this by specifying quality of service or QoS, we use Quality of Service class depending on how important a task is. Below are the Quality of Services.


    .userInteractive:

    user-interactive tasks have the highest priority of the system and use this class for tasks or queues that interact with the user or actively update your apps user interface for example use this class for animations or for tracking events interactively.

    .userInitiated:

    user-initiated tasks are second priority after the user-interactive. user-interactive tasks in their priority on the system you assign this class to tasks that provide immediate results for something the user is doing or that would prevent the user from using your app, for example, you might use this quality of service class to load the content of an email that you want to display to the user.

    The next two types are lower in priority for execution.

    .utility:

    Utility tasks have a lower priority than user initiated and user interactive tasks but a higher priority event background tasks you assign this quality of service class to tasks that do not permit the user from continuing to use your app. for example you might assign this class to long running tasks whose progress the user doesn't have to follow actively.


    .background:

    Background tasks have the lowest priority of all tasks you assign this class to tasks or dispatched queues that you use to perform work while your app is running in the background like maintenance tasks or cleanup.

    So the four priorities are listed here in the order of priority.

    . userInteractive 
    . userInitiated 
    . utility 
    . background

    If you don't specify a QoS.

    .userInteractive 
    .userInitiated
    .default 
    .utility 
    .background

    .default:

    It will be say assigned the default case The default task has a lower priority than user-interactive and user-initiated. Assign this class to the task that your app initiates or performs active work on the user’s behalf.

    // User-interactive
        DispatchQueue.global(qos: .userInteractive).async {
        // Event handling task & Animation task
        // Task compete then update UI (in main queue)
        }
        
        // User-initiated:
        DispatchQueue.global(qos: .userInitiated).async {
        // Load conent of email, etc
        }
        
        // Defaul
        DispatchQueue.global(qos: .default).async {
        // task that your app initiates
        // performs active work on the user's behalf
        }
        
        // Utility
        DispatchQueue.global(qos: .utility).async {
        //Low priority task
        }
        
        // Background
        DispatchQueue.global(qos: .background).async {
        //  task which needs to be executed when the app is running in the background
        }
    There are two ways that you can add code tears queue either synchronously or asynchronously.

    Synchronous:

    When a work item is executed synchronously with the sync method a program waits until the execution finishes before the method returns that is before the next line of code following the code block gets executed this means that it will block the user from doing anything until the code is completed the code block is executed as the closure on either the main or background queue like this.

    DispatchQueue.main.sync{
     //code to be execute
     }
    

    Asynchronous:

    When a work item is executed asynchronously the async method the method call returns immediately and the execution of the closure is done the same way as above we just use async instead of sync both synchronous and asynchronous executions can be done on the main or background threads but the fact of the matter is you almost never use asynchronous execution so we'll focus on asynchronous.
    DispatchQueue.global().async{ 
    //code to be execute 
    }


    If you enjoyed this article please share.

    Thanks for reading!!

    Similar solutions you may also like...


    Post a Comment

    0 Comments