To understand GCD, you need to be comfortable with several concepts related to concurrency and threading.
Concurrency
In iOS, a process or application consists of one or more threads. The operating system scheduler manages the threads independently of each other. Each thread can execute concurrently, but it’s up to the system to decide if this happens, when this happens, and how it happens.
Single-core devices achieve concurrency through a method called time-slicing. They run one thread, perform a context switch, then run another thread.
Multi-core devices, on the other hand, execute multiple threads at the same time via parallelism.
GCD is built on top of threads. Under the hood it manages a shared thread pool. With GCD you add blocks of code or work items to dispatch queues and GCD decides which thread to execute them on.
As you structure your code, you’ll find code blocks that can run simultaneously and some that should not. This then allows you to use GCD to take advantage of concurrent execution.
Note that GCD decides how much parallelism it requires based on the system and available system resources. It’s important to note that parallelism requires concurrency, but concurrency does not guarantee parallelism.
Basically, concurrency is about structure while parallelism is about execution.
Queues
As mentioned before, GCD operates on dispatch queues through a class aptly named DispatchQueue. You submit units of work to this queue and GCD will execute them in a FIFO order (First In, First Out), guaranteeing that the first task submitted is the first one started.
Dispatch queues are thread-safe which means that you can access them from multiple threads simultaneously. The benefits of GCD are apparent when you understand how dispatch queues provide thread safety to parts of your own code. The key to this is to choose the right kind of dispatch queue and the right dispatching function to submit your work to the queue.
Queues can be either serial or concurrent. Serial queues guarantee that only one task runs at any given time. GCD controls the execution timing. You won’t know the amount of time between one task ending and the next one beginning:
Concurrent queues allow multiple tasks to run at the same time. The queue guarantees tasks start in the order you add them. 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.
This is by design: your code shouldn’t rely on these implementation details.
See the sample task execution below:
Notice how Task 1, Task 2, and Task 3 start quickly one after the other. On the other hand, Task 1 took a while to start after Task 0. Also notice that while Task 3 started after Task 2, it finished first.
The decision of when to start a task is entirely up to GCD. 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.
GCD provides three main types of queues:
- Main queue: runs on the main thread and is a serial queue.
- Global queues: concurrent queues that are shared by the whole system. There are four such queues with different priorities : high, default, low, and background. The background priority queue has the lowest priority and is throttled in any I/O activity to minimize negative system impact.
- Custom queues: queues that you create which can be serial or concurrent. Requests in these queues actually end up in one of the global queues.
When sending tasks to the global concurrent queues, you don’t specify the priority directly. Instead, you specify a Quality of Service (QoS) class property. This indicates the task’s importance and guides GCD in determining the priority to give to the task.
The QoS classes are:
- User-interactive: This represents tasks that must complete 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: The user initiates these asynchronous tasks from the UI. Use them when the user is waiting for immediate results and for tasks required to continue user interaction. They execute in 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, continuous 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.
Synchronous vs. Asynchronous
With GCD, you can dispatch a task either synchronously or asynchronously.
A synchronous function returns control to the caller after the task completes. You can schedule a unit of work synchronously by calling DispatchQueue.sync(execute:).
An asynchronous function returns immediately, ordering the task to start but not waiting for it to complete. Thus, an asynchronous function does not block the current thread of execution from proceeding on to the next function. You can schedule a unit of work asynchronously by calling DispatchQueue.async(execute:).
Managing Tasks
You’ve heard about tasks quite a bit by now. For the purposes of this tutorial you can consider a task to be a closure. Closures are self-contained, callable blocks of code you can store and pass around.
Each task you submit to a DispatchQueue is a DispatchWorkItem. You can configure the behavior of a DispatchWorkItem such as its QoS class or whether to spawn a new detached thread.
www.raywenderlich.com/5370-grand-central-dispatch-tutorial-for-swift-4-part-1-2
Grand Central Dispatch Tutorial for Swift 4: Part 1/2
Learn all about multithreading, dispatch queues, and concurrency in the first part of this Swift 4 tutorial on Grand Central Dispatch.
www.raywenderlich.com
'Programming > Swift' 카테고리의 다른 글
continue vs. return vs. break (0) | 2021.03.04 |
---|---|
if let vs. guard let (0) | 2021.03.04 |
[ios] Self-Sizing Table View Cells (0) | 2021.01.22 |
Protocol: CLLocationManagerDelegate (0) | 2021.01.19 |
Optional (0) | 2021.01.14 |