From 0bdba4102eb9b9d03878bcddfac076278f09bef1 Mon Sep 17 00:00:00 2001 From: Mayank Kumar Date: Fri, 1 Sep 2017 16:10:44 +0530 Subject: [PATCH 1/6] gcd blog --- _posts/2017-09-01-typed-GCD.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 _posts/2017-09-01-typed-GCD.md diff --git a/_posts/2017-09-01-typed-GCD.md b/_posts/2017-09-01-typed-GCD.md new file mode 100644 index 0000000..e69de29 From 909dc9aff22c14932361e1dfeb556874fbadd758 Mon Sep 17 00:00:00 2001 From: Mayank Kumar Date: Fri, 1 Sep 2017 16:37:14 +0530 Subject: [PATCH 2/6] file name changed --- _posts/2017-09-01-Grand Cental Dispatch.md | 164 +++++++++++++++++++++ _posts/2017-09-01-typed-GCD.md | 0 2 files changed, 164 insertions(+) create mode 100644 _posts/2017-09-01-Grand Cental Dispatch.md delete mode 100644 _posts/2017-09-01-typed-GCD.md diff --git a/_posts/2017-09-01-Grand Cental Dispatch.md b/_posts/2017-09-01-Grand Cental Dispatch.md new file mode 100644 index 0000000..a5712aa --- /dev/null +++ b/_posts/2017-09-01-Grand Cental Dispatch.md @@ -0,0 +1,164 @@ +--- +layout: post +title: "GCD (Grand Central Dispatch)- Multithreading in iOS" +date: 2017-09-01 01:20:00 +author: mayank +categories: Technical iOS +--- +# GCD (Grand Central Dispatch) + +Managing threads in an application that uses threads extensively can sometimes be very cumbersome task making the developer to worry more about the threads rather than business logic.So, here comes the role of GCD! + +## Basic Introduction :- +`GCD` (libdispatch) is a system level library (written in C) that takes all this responsibility of thread management and let the developer to focus on the business logic rather than managing threads. + +`GCD` is built on top of threads. Under the hood it manages a shared thread pool. + + +## Dispatch Queue +The dominating concept in `GCD` is the `DispatchQueue`. +- Tasks (in the form of blocks of code) are submitted to dispatch queues that execute them in FIFO order guaranteeing that the queue that comes first for execution will also start first. +- These dispatch queues execute the tasks serially or concurrently depending on their type- Serial or Concurrent. + +### Serial Dispatch Queue +- In a serial `DispatchQueue`, only one task can run at a time. +- GCD controls the execution timing. You won’t know the amount of time between one task ending and the next one beginning. + +![Strongly Typed]({{https://koenig-media.raywenderlich.com/uploads/2014/09/Serial-Queue-Swift.png) + Image Source - www.raywenderlich.com/ + +## Concurrent Dispatch Queue +- In a concurrent `DispatchQueue`, multiple tasks can run at a time . +- Tasks are guaranteed to start in the order they were added. Tasks can finish in any order and you have no knowledge of the time it will take for the next task to start, nor the number of tasks that are running at any given time. + +![Strongly Typed]({{https://koenig-media.raywenderlich.com/uploads/2014/09/Concurrent-Queue-Swift.png) + Image Source - www.raywenderlich.com/ + + It is `GCD` that decides when to start a task. If the execution time of one task overlaps with another, it’s up to GCD to determine if it should run on a different core, if one is available, or instead to perform a context switch to run a different task. + + Each task submitted to a queue is processed on a pool of threads managed by the system. + When a task is submitted to a dispatch queue, it is `GCD` that decides which thread to execute it on.So, you only needs to interact with GCD dispatch queues and not the threads. + + Tasks can be submitted to dispatch queues either synchronously or asynchronously. + + The key to use GCD is to choose the right kind of dispatch queue and the right dispatching function (i.e. _sync_, _async_) to submit your work to the queue. + + ## Dispatching functions (Synchronous and Asynchronous) + With `GCD`, you can dispatch a task either synchronously or asynchronously. + + A _synchronous_ function returns control to the caller after the task is completed. + + An _asynchronous_ function returns immediately, ordering the task to be done but not waiting for it. Thus, an asynchronous function does not block the current thread of execution from proceeding on to the next function. + + ## Types of dispatch queues + +**Main dispatch queue** - This is a globally available serial queue and it executes the tasks submitted to it on the application’s main thread. + +**Global dispatch queue** - These are concurrent queues and are shared by the whole system. There are four such queues with different priorities : high, default, low, and background. + +When setting up the global concurrent queues, you don’t specify the priority directly. Instead you specify a `Quality of Service` (QoS) class property. This will indicate the task’s importance and guide GCD into determining the priority to give to the task. + +## Types of `QoS` classes +**User-interactive**: This represents tasks that need to be done immediately in order to provide a nice user experience. Use it for UI updates, event handling and small workloads that require low latency. The total amount of work done in this class during the execution of your app should be small. This should run on the main thread. + +**User-initiated**: This represents tasks that are initiated from the UI and can be performed asynchronously. It should be used when the user is waiting for immediate results, and for tasks required to continue user interaction. This will get mapped into the high priority global queue. +Utility: This represents long-running tasks, typically with a user-visible progress indicator. Use it for computations, I/O, networking, continous data feeds and similar tasks. This class is designed to be energy efficient. This will get mapped into the low priority global queue. + +**Background**: This represents tasks that the user is not directly aware of. Use it for prefetching, maintenance, and other tasks that don’t require user interaction and aren’t time-sensitive. This will get mapped into the background priority global queue. +The currently executing tasks run on distinct threads that are managed by the dispatch queue. The exact number of tasks executing at any given point is variable and depends on system conditions. + +**Custom Queues** - These are the queues that you create by yourself and these can be serial or concurrent. These actually trickle down into being handled by one of the global queues. + +## Examples + +### Working with system queues + +#### Main Queue +##### Submitting a task to the main queue asynchronously + + +Since, the task is submitted to the main queue asynchronously, so the calling thread won’t wait for the completion for submitted task and will return immediately. + +##### Submitting a task to the main queue asynchronously that will be executed after some delay + +{% highlight swift %} + DispatchQueue.main.asyncAfter(deadline: .now() + delay) { + //task to be performed on main thread after 1 second of submission + } +{% endhighlight %} + +#### Global Concurrent Queue + +{% highlight swift %} +DispatchQueue.global(qos: .utility).async { + // Asynchronous code running on the low priority queue +} +{% endhighlight %} + +{% highlight swift %} +DispatchQueue.global(qos: .userInitiated).sync { + // Synchronous code running on the high prioriy queue +} +{% endhighlight %} + +### Working with custom queue + +##### Custom Serial Queue + +{% highlight swift %} +let customSerialQueue = DispatchQueue(label: "com.appName.myCustomSerialQueue") +customSerialQueue.async { + // Code +} +{% endhighlight %} + +##### Custom Concurrent Queue +{% highlight swift %} +let customConcurrentQueue = DispatchQueue(label: "com.appName.myCustomConcurrentQueue", attributes: .concurrent) +customConcurrentQueue.async { + // Code +} +{% endhighlight %} + +#### Performing background tasks and then updating the UI + +{% highlight swift %} +DispatchQueue.global(qos: .background).async { + // Do some background work + DispatchQueue.main.async { + // Update the UI to indicate the work has been completed + } +} +{% endhighlight %} + +#### Be careful of deadlocks with serial queues + +{% highlight swift %} +let customSerialQueue = DispatchQueue(label: "com.appName.myCustomSerialQueue") + +customSerialQueue.sync { + // Synchronous code + customSerialQueue.sync { + // This code will never be executed and the app is now in deadlock + } +} +{% endhighlight %} + +##### Beware of submitting task synchronously on the main thread from another thread + +{% highlight swift %} +DispatchQueue.global(qos: .utility).sync { + // Background Task + DispatchQueue.main.sync { + // App will crash + } +} +{% endhighlight %} + +### Inspiration + +- https://www.raywenderlich.com/148513/grand-central-dispatch-tutorial-swift-3-part-1 + +- https://medium.com/modernnerd-code/grand-central-dispatch-crash-course-for-swift-3-8bf2652c1cb8 + +- https://developer.apple.com/library/content/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html diff --git a/_posts/2017-09-01-typed-GCD.md b/_posts/2017-09-01-typed-GCD.md deleted file mode 100644 index e69de29..0000000 From 1c3103b4e650f5718804405d7bdcd3b84d89c65c Mon Sep 17 00:00:00 2001 From: Mayank Kumar Date: Mon, 4 Sep 2017 13:57:00 +0530 Subject: [PATCH 3/6] minor changes --- _posts/2017-09-01-Grand Cental Dispatch.md | 35 ++++++++++++---------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/_posts/2017-09-01-Grand Cental Dispatch.md b/_posts/2017-09-01-Grand Cental Dispatch.md index a5712aa..ed51d2b 100644 --- a/_posts/2017-09-01-Grand Cental Dispatch.md +++ b/_posts/2017-09-01-Grand Cental Dispatch.md @@ -76,64 +76,67 @@ The currently executing tasks run on distinct threads that are managed by the di #### Main Queue ##### Submitting a task to the main queue asynchronously +```swift + DispatchQueue.main.async { + perform some task on main thread + } +``` Since, the task is submitted to the main queue asynchronously, so the calling thread won’t wait for the completion for submitted task and will return immediately. ##### Submitting a task to the main queue asynchronously that will be executed after some delay -{% highlight swift %} +```swift DispatchQueue.main.asyncAfter(deadline: .now() + delay) { //task to be performed on main thread after 1 second of submission } -{% endhighlight %} +``` #### Global Concurrent Queue -{% highlight swift %} +```swift DispatchQueue.global(qos: .utility).async { // Asynchronous code running on the low priority queue } -{% endhighlight %} -{% highlight swift %} DispatchQueue.global(qos: .userInitiated).sync { // Synchronous code running on the high prioriy queue } -{% endhighlight %} +``` ### Working with custom queue ##### Custom Serial Queue -{% highlight swift %} +```swift let customSerialQueue = DispatchQueue(label: "com.appName.myCustomSerialQueue") customSerialQueue.async { // Code } -{% endhighlight %} +``` ##### Custom Concurrent Queue -{% highlight swift %} +```swift let customConcurrentQueue = DispatchQueue(label: "com.appName.myCustomConcurrentQueue", attributes: .concurrent) customConcurrentQueue.async { // Code } -{% endhighlight %} +``` #### Performing background tasks and then updating the UI -{% highlight swift %} +```swift DispatchQueue.global(qos: .background).async { // Do some background work DispatchQueue.main.async { // Update the UI to indicate the work has been completed } } -{% endhighlight %} +``` #### Be careful of deadlocks with serial queues -{% highlight swift %} +```swift let customSerialQueue = DispatchQueue(label: "com.appName.myCustomSerialQueue") customSerialQueue.sync { @@ -142,18 +145,18 @@ customSerialQueue.sync { // This code will never be executed and the app is now in deadlock } } -{% endhighlight %} +``` ##### Beware of submitting task synchronously on the main thread from another thread -{% highlight swift %} +```swift DispatchQueue.global(qos: .utility).sync { // Background Task DispatchQueue.main.sync { // App will crash } } -{% endhighlight %} +``` ### Inspiration From 4dd045c636032178357c7fea3849af44e781afd0 Mon Sep 17 00:00:00 2001 From: Mayank Kumar Date: Mon, 4 Sep 2017 14:06:29 +0530 Subject: [PATCH 4/6] minor changes --- _posts/2017-09-01-Grand Cental Dispatch.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2017-09-01-Grand Cental Dispatch.md b/_posts/2017-09-01-Grand Cental Dispatch.md index ed51d2b..bb0891e 100644 --- a/_posts/2017-09-01-Grand Cental Dispatch.md +++ b/_posts/2017-09-01-Grand Cental Dispatch.md @@ -16,7 +16,7 @@ Managing threads in an application that uses threads extensively can sometimes b ## Dispatch Queue -The dominating concept in `GCD` is the `DispatchQueue`. +The dominating concept in `GCD` is the [DispatchQueue](https://developer.apple.com/library/content/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html). - Tasks (in the form of blocks of code) are submitted to dispatch queues that execute them in FIFO order guaranteeing that the queue that comes first for execution will also start first. - These dispatch queues execute the tasks serially or concurrently depending on their type- Serial or Concurrent. From 49b3bb5b10949decc326d5ad7b56a586e140a764 Mon Sep 17 00:00:00 2001 From: Mayank Kumar Date: Mon, 4 Sep 2017 14:13:07 +0530 Subject: [PATCH 5/6] minor change --- _posts/2017-09-01-Grand Cental Dispatch.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/_posts/2017-09-01-Grand Cental Dispatch.md b/_posts/2017-09-01-Grand Cental Dispatch.md index bb0891e..d3ac7f7 100644 --- a/_posts/2017-09-01-Grand Cental Dispatch.md +++ b/_posts/2017-09-01-Grand Cental Dispatch.md @@ -76,10 +76,10 @@ The currently executing tasks run on distinct threads that are managed by the di #### Main Queue ##### Submitting a task to the main queue asynchronously -```swift - DispatchQueue.main.async { - perform some task on main thread - } +``` + DispatchQueue.main.async { + perform some task on main thread + } ``` Since, the task is submitted to the main queue asynchronously, so the calling thread won’t wait for the completion for submitted task and will return immediately. From 3f3302b74cc6a8bb1a993e14582a6c28dd14ced2 Mon Sep 17 00:00:00 2001 From: Mayank Kumar Date: Mon, 4 Sep 2017 14:43:43 +0530 Subject: [PATCH 6/6] minor changes --- _posts/2017-09-01-Grand Cental Dispatch.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/_posts/2017-09-01-Grand Cental Dispatch.md b/_posts/2017-09-01-Grand Cental Dispatch.md index d3ac7f7..bc7aa4f 100644 --- a/_posts/2017-09-01-Grand Cental Dispatch.md +++ b/_posts/2017-09-01-Grand Cental Dispatch.md @@ -76,10 +76,10 @@ The currently executing tasks run on distinct threads that are managed by the di #### Main Queue ##### Submitting a task to the main queue asynchronously -``` - DispatchQueue.main.async { +```swift + DispatchQueue.main.async { perform some task on main thread - } + } ``` Since, the task is submitted to the main queue asynchronously, so the calling thread won’t wait for the completion for submitted task and will return immediately.