Concurrency In Swift

What is Concurrency?

 
Concurrency is a process in which a program can perform multiple tasks simultaneously, executing tasks or processes in the background. The concurrency turns the decomposability of program, algorithm or problem into order-independent or partially ordered components or units.
 

Why use Concurrency?

 
It's critical to ensure that your app runs as smoothly as possible to ensure that user wait time is reduced. For example, scrolling through a table of images is one of the more common situations in which an end-user is impacted by a lack of concurrency. If you need to download images from a network or perform some type of image processing before displaying it, the scrolling will be stuck and you will be forced to display multiple indicators instead of an expected image.
 

How to use Concurrency?

 
At a high level, you need to structure your app so that some tasks can run at the same time. Multiple tasks that modify the same resource (i.e. variable) can't run at the same time unless you make them thread-safe.
 
Tasks which access different resources, or read-only shared resources, can all be accessed via different threads to allow for much faster processing.
 
There are two API's you will use when making your concurrent:
  1. Grand Central Dispatch (GCD)
  2. Operations

Grand Central Dispatch

 
GCD is Apple's implementation of C's libdispatch library. Its purpose is to queue up tasks, either method or closure, that can run in parallel depending or the availability of resources. It then executes the tasks on an available processor core.
 
GCD's tasks are so lightweight to enqueue that Apple, in its GCD technical brief, stated that only 15 instructions are required for implementation, whereas creating traditional threads could require several hundred instructions.
 
All of the tasks GCD manages for you are placed into GCD first-in, first-out(FIFO) queues. Each task that you submit to a queue is then executed against a pool of threads fully managed by the system.
 
Declaration -
  1. DispatchQueue.main.async {  
  2.     // Run async code on the main queue  
  3.    
  4. }  
DispatchQueue -  An Object that manages the execution of tasks serially or concurrently on your app's main thread or background thread. 

Note
There is no guarantee as to which thread your task will execute against. 
 

Synchronous and Asynchronous task

 
Work is placed on queue either synchronously or asynchronously. When running a task synchronously, your app will wait and block the current run loop until execution finishes before moving on to the next task. A task that runs asynchronously will start and return execution immediately. This way, the app is free to run other tasks while the first one is executing.
 
Note
It's important to keep in mind that while the queue is FIFO based, it does not ensure that tasks will finish in the order you submit them. The FIFO procedure applies to when the task starts, not when it finishes.
 

Using Concurrent Dispatch Queue 

 
Let's take an example using concurrent dispatch - the below example handles image download from URLs:
  1. import UIKit  
  2.   
  3. let imageURLs = [  
  4.  "https://www.planetware.com/photos-large/F/france-paris-eiffel-tower.jpg",  
  5.  "https://adriatic-lines.com/wp-content/uploads/2015/04/canal-of-Venice.jpg",  
  6.  "https://www.planetware.com//wpimages/2019/09/connecticut-mystic-top-things-to-do-mystic-river-bascule-drawbridge-downtown-mystic.jpg",  
  7.  "https://www.planetware.com/photos-large/CAY/best-luxury-all-inclusive-world-nihi-sumba.jpg"  
  8. ]  
  9.   
  10. class ViewController: UIViewController {  
  11.     @IBOutlet weak var imgFirst: UIImageView!  
  12.     @IBOutlet weak var imgSecond: UIImageView!  
  13.     @IBOutlet weak var imgThird: UIImageView!  
  14.     @IBOutlet weak var imgFourth: UIImageView!  
  15.       
  16.     override func viewDidLoad() {  
  17.         super.viewDidLoad()  
  18.         // Do any additional setup after loading the view.  
  19.     }  
  20.   
  21.     @IBAction func didStartAction(_ sender: Any) {  
  22.         let queue =  DispatchQueue(label:"com.queue.concurrencyDemo")  
  23.         queue.async{  
  24.             let firstImg = Downloader.downloadImageWithURL(url: imageURLs[0])  
  25.             DispatchQueue.main.async {  
  26.                  self.imgFirst.image = firstImg  
  27.             }  
  28.         }  
  29.         queue.async{  
  30.             let img2 = Downloader.downloadImageWithURL(url: imageURLs[1])  
  31.             DispatchQueue.main.async {  
  32.                 self.imgSecond.image = img2  
  33.             }  
  34.         }  
  35.           
  36.         queue.async {  
  37.              let img3 = Downloader.downloadImageWithURL(url: imageURLs[2])  
  38.               DispatchQueue.main.async {  
  39.                 self.imgThird.image = img3  
  40.             }  
  41.         }  
  42.   
  43.         queue.async{  
  44.             let img4 = Downloader.downloadImageWithURL(url: imageURLs[3])  
  45.             DispatchQueue.main.async{  
  46.                 self.imgFourth.image = img4  
  47.             }  
  48.         }  
  49.     }  
  50.       
  51. }  
  52.   
  53. class Downloader {  
  54.     class func downloadImageWithURL(url:String) -> UIImage! {  
  55.         if let data = NSData(contentsOf: NSURL(string: url)! as URL){  
  56.             return UIImage(data: data as Data)  
  57.         }  
  58.         return UIImage.init()  
  59.     }  
  60. }  
 
  
 
I hope you understood Concurrency using Grand Central Dispatch Queue(GCD). Soon, I will write an article about NSOperationQueue to achieve concurrency.
 
Thanks, Cheers!!