program. A process has its own virtual memory space and system resources. • Thread is a f low of execution in a process. • Task is the abstract concept of work that needs to be performed. User Login task iOS App Process … main thread thread 1 thread N UI drawing Sending request to a backend
program. A process has its own virtual memory space and system resources. • Thread is a f low of execution in a process. • Task is the abstract concept of work that needs to be performed. macOS Main App Process … main thread thread 1 thread N User Login task UI drawing Sending request to a backend Background Service Process Widget
task runs at any given time. • Concurrent queue - allow multiple tasks to run at the same time. The queue guarantees that the tasks start in the order you add them. Serial Queue Task 1 Task 2 Task 3 Task 4 Concurrent Queue Task 1 Task 2 Task 3 Task 4
main thread and is a serial queue. • Global queues - concurrent queues that are shared by the whole system. There are four such queues with di ff erent priorities : high, default, low, and background. • Custom queues - queues that you create which can be serial or concurrent. Main Queue Drawing UI Drawing More Drawing Global and Custom Queues User-interactive User-initiated Utility Background With same QoS ☝
the caller after the task completes. DispatchQueue.sync(execute:) • An asynchronous function returns immediately, ordering the task to start but not waiting for it to complete. DispatchQueue.async(execute:) a way to dispatch a task Serial Queue Sync task Async task Async task Sync task Async task Async task Concurrent Queue Async task
a UITableViewCell. To implement 😸 Title Subtitle Title Subtitle Global (Concurrent) Queue Main (Serial) Queue Set image URL Download Image Data Set image
as a single unit. • DispatchSemaphore - an object that controls access to a resource across multiple execution contexts through use of a traditional counting semaphore. Concurrent Queue, let group = DispatchGroup() group.notify() Async task group.enter() group.leave() Async task group.enter() group.leave() Sync task group.enter() group.leave() Concurrent Queue, let semaphore = DispatchSemaphore(value: 2) semaphore.wait() Async task Async task Async task Async task semaphore.wait() semaphore.wait() semaphore.wait() semaphore.signal() semaphore.signal() semaphore.signal() semaphore.signal()
consists of 3 parts: general, family, and work infos. This is 3 di ff erent API calls. • Only when all information is received - display it on the screen. To implement 🧑🦱 Name Age Family: - 👱 Mom - 👨 Dad - 👶 Brother - 🐆 Cat Work: MacPaw
Get General Info group.enter() group.leave() Get Family Info group.enter() group.leave() Get Work Info group.enter() group.leave() • You need to fetch a User Info that consists of 3 parts: general, family, and work infos. This is 3 di ff erent API calls. • Only when all information is received - display it on the screen.
semaphore.wait() Download semaphore.signal() semaphore.wait() Download semaphore.signal() semaphore.wait() Download semaphore.signal() semaphore.wait() Download semaphore.signal() semaphore.wait() Download semaphore.signal() semaphore.wait() Download semaphore.signal() semaphore.wait() Download semaphore.signal() semaphore.wait() Download semaphore.signal() • There is a Song downloader app. The user is allowed to download 3 songs at once.
Each subclass represents a speci f ic task; • can be paused, resumed, and cancelled; • can depend on other Operations; • is a key-value coding (KVC) and key-value observing (KVO) compliant; • synchronous by default;
Each subclass represents a speci f ic task; • can be paused, resumed, and cancelled; • can depend on other Operations; • is a key-value coding (KVC) and key-value observing (KVO) compliant; • synchronous by default; • For non-concurrent operations, you typically override only one method: main() • If you are creating a concurrent operation, you need to override the following methods and properties at a minimum: start() isAsynchronous isExecuting isFinished
operations; • is key-value coding (KVC) and key-value observing (KVO); • allows you to specify the maximum number of queued operations that can run simultaneously; var queue = OperationQueue() queue.maxConcurrentOperationCount = 2 Async Operation Async Operation Sync Operation Async Operation
Age 👩🦰 Friend 3 Age 👨 Friend 4 Age 👳 Friend 5 Age … • Get a list of your friends (name, age, photo), display it in the table. • Each photo of your friend should be modi f ied with Instagram f ilter. • Display progress bar during all processes.
Data Filtering OperationQueue Filter Image Report Progress For visible cells Download Image Report Progress Report Progress • Get a list of your friends (name, age, photo), display it in the table. • Each photo of your friend should be modi f ied with Instagram f ilter. • Display progress bar during all processes.
Filter Image For visible cells Download Image Download Friends Data Report Progress Report Progress Download Image Report Progress Report Progress Filter Image Report Progress Report Progress • Get a list of your friends (name, age, photo), display it in the table. • Each photo of your friend should be modi f ied with Instagram f ilter. • Display progress bar during all processes.
critical portion of the code and can halt the application's run loop entirely. • In the context of GCD, you should be very careful when using the dispatchQueue.sync { } calls as you could easily get yourself in situations where two synchronous operations can get stuck waiting for each other. let serialQueue = DispatchQueue(label: "MySerialQueue") serialQueue.async { serialQueue.sync { // <-- deadlock for i in 0..<5 { print(i) } } } Serial Queue Sync Task Async Task waits waits Important Attempting to synchronously execute a work item on the main queue results in deadlock.
task blocks a high priority task from executing, which e ff ectively inverts their priorities. • GCD allows for di ff erent levels of priority on its background queues, so this is quite easily a possibility. enum Color: String { case blue = "🔵 " case white = "⚪ " } func output(color: Color, times: Int) { for _ in 1...times { print(color.rawValue) } } let starterQueue = DispatchQueue(label: "com.starter", qos: .userInteractive) let utilityQueue = DispatchQueue(label: "com.utility", qos: .utility) let backgroundQueue = DispatchQueue(label: "com.background", qos: .background) let count = 10 starterQueue.async { backgroundQueue.async { output(color: .white, times: count) } backgroundQueue.async { output(color: .white, times: count) } utilityQueue.async { output(color: .blue, times: count) } utilityQueue.async { output(color: .blue, times: count) } // priority inverted here backgroundQueue.sync {} }
task blocks a high priority task from executing, which e ff ectively inverts their priorities. • GCD allows for di ff erent levels of priority on its background queues, so this is quite easily a possibility. Concurrent .userInteractive queue Concurrent .utility queue Concurrent .background queue Async Operation Sync Operation Async Operation Async Operation Async Operation GCD resolves this inversion by raising the QoS of the entire queue to temporarily match the high QoS task; consequently, all the tasks on the .background queue end up running at .userInteractive QoS, which is higher than the utility QoS. And that’s why the utility tasks f inish last!
thread is creating a data resource while another thread is accessing it. • This is a synchronization problem, and can be solved using locks, semaphores, serial queues, or a barrier dispatch if you're using concurrent queues in GCD. let concurrent = DispatchQueue(label: "com.concurrent", attributes: [ .concurrent ]) var array = [1, 2, 3, 4, 5] func race() { concurrent.async { for i in array { // read access print(i) } } concurrent.async { for i in 0..<10 { array.append(i) // write access } } } for _ in 0...100 { race() } 4 1 6 1 1 4 1 Swift/ContiguousArrayBuffer.swift:580: Fatal error: Index out of range 3 0 3
you run the risk of thread explosion if you’re not careful. • This can happen when you try to submit tasks to a concurrent queue that is currently blocked (e.g. with a semaphore, sync, or some other way.) • Your tasks will run, but the system will likely end up spinning up new threads to accommodate these new tasks, and threads aren’t cheap. More related to old devices
dependencies. • The Operation and OperationQueue classes have a number of properties that can be observed, using KVO. • Operations can be paused, resumed, and cancelled. • Ability to specify the maximum number of queued operations that can run simultaneously. Comparison
need to dispatch a block of code to a serial or concurrent queue. • The Operation API is great for encapsulating well-de f ined blocks of functionality. What would be the best choice?
have direct control over the threads you create, • you need f ine-grained control over thread priorities • interfacing with some other subsystem that vends/ consumes thread objects directly and you need to stay on the same page with it. • Useful in real-time applications. NSThread GCD Operation
model was de f ined. Many of the POSIX conformant Operating Systems provide an implementation of pthreads. macOS being one of them, gives us access to pthreads . C-based interface. pthread NSThread GCD Operation