
In a developer’s life it’s a common task to write a program and ask system to perform it. Understanding how the system performs a task helps us utilise its full potential.
In this blog, initially we are going to see how a hardware performs a task. Later we will discuss about OperationQueue – a programming model which automatically scales based on available hardware resource.
History
Earlier days developers used thread to execute a task. Thread is low level tool and it doesn’t scale as the number of core increases. It’s challenging to create multiple threads and keeping them synchronised efficiently.
In order to resolve it, instead of creating threads manually, let us assign our task in a queue and asks the system to perform it. By letting the system to manage threads, our app gains maximum scalability with simpler and efficient programming model.
GCD and OperationQueue are such models which creates a way for our program to take advantage of multiple cores which handles dynamically changing system conditions. Today we are going to see a brief about OperationQueue before that let’s see how a single and multiple core system executes a task.
Concurrency
It refers to dealing lot of things at once. Let’s understand it by an example: In a day today life apart from developing, we have lots of task to perform like read/reply mail, followup a task, read blog, plan meetings etc., But if you see its really complex to perform all those tasks at a time. All we can do is, we will switch between different tasks based on resources[time, priorities, our energy]. Following the same way in a single core environment multiple tasks will execute concurrently at a time by switching the context.
Parallelism
It refers to doing lots of things at once. As per the previous example, if we have multiple persons to perform each task, we can execute all at a time without interrupting others. So in multi core environment multiple thread will execute tasks via parallelism.
Concurrency vs Parallelism
- Parallelism needs hardware with multicore processing units whereas Concurrency don’t need it.
- Concurrency requires 2 task to exist whereas Parallelism don’t need it.
- Parallelism assigns each task for a core to execute whereas Concurrency execute all tasks by switching tasks at a same time.
Credits: https://joearms.github.io/published/2013-04-05-concurrent-and-parallel-programming.html
What’s OperationQueue?
OperationQueue is a high level abstraction of GCD. It’s a queue that regulate the execution of a task. In OperationQueue when we add tasks to execute, unlike a queue it won’t execute task in FIFO order. It executes tasks based on the priorities and readiness of a task to execute. In an operation queue, we could add a task as a block or as an Operation object.
– Execute a task as a block in the OperationQueue
let operationQueue = OperationQueue() let block = { () in print("Execute a block task") } operationQueue.addOperation(block)
What’s Operation?
Another better way to execute a task is using Operation. It’s an abstract class which represent a single unit work to be executed. It provides us much flexibility to write code in an object orientated way. We can use Operations either by subclassing it or by using system defined subclasses [InvocationOperation or BlockOperation]. It has more benefits like executing based on priorities, adding dependencies and cancelling operations
– Executing a task using a block operation
let blockOperation = BlockOperation { print("Execute a task using BlockOperation") } operationQueue.addOperation(blockOperation)
– Executing a custom operation
class UploadOperation: Operation { let data: Data var serverURL: URL! init(uploadData: Data) { data = uploadData } override func main() { guard !isCancelled else { return } // Upload a media to aws server and get the url print("Execute a task using a Custom Operation") } } let customOperation = UploadOperation(uploadData: Data())
– Operation has the potential to add dependency between operations. The object oriented syntax helps us to pass objects around the operations.
class MapOperation: Operation { override func main() { guard !isCancelled, let uploadOperation = dependencies.first as? UploadOperation else { return } print(uploadOperation.serverURL ?? "Some server url") // Map the uploaded url to an api } } let mapOperation = MapOperation() mapOperation.addDependency(customOperation) operationQueue.addOperations([mapOperation, customOperation], waitUntilFinished: true)
So by the above example, we can use Operation to execute a task in object oriented way which provides flexibility to add dependencies.
Conclusion
In addition, operation has added advantages like cancelling a task, KVO/KVC and QueuePriority. In my next blog, we can see the cancelling operations, concurrent, synchronous vs asynchronous operations and their states.
Srikanth T,
iOS Development team,
Mallow technologies.