Recently, i am learning concurrency in swift. According to apple's document in NSOperation class reference :
When you add an operation to an operation queue, the queue ignores the value of the asynchronous property and always calls the start method from a separate thread. Therefore, if you always run operations by adding them to an operation queue, there is no reason to make them asynchronous.
does it mean synchronous in a separate thread is the same as asynchronous? and when i do the test with the following code, the operation indeed doesn't block the current main thread.
let operationQueue = NSOperationQueue()
let operation = NSBlockOperation(){
//do some task here
}
operationQueue.addOperation(operation)
so if it is true, then why should we create concurrency subclass of NSOperation?
Oh, NSOperation. Such a bizarre history you have.
NSOperation is relatively old (in iOS terms; fairly modern in ObjC terms). It was added in OS X 10.5. Before OS X 10.6/iOS 4, there were no NSBlockOperation objects. There were no blocks at all. So the only way to make an operation was to subclass or use NSInvocationOperation. Both approaches are cumbersome, but were still easier and more powerful than the older approach of using NSThread directly.
(This was right at the time when multi-core became a thing. 10.5 was famous for adding Core Animation which was I believe the first major preemptive multitasking framework in Cocoa. Before 10.5, most things were done with the runloop and cooperative multitasking, which is actually very efficient and effective for single-core systems. But it doesn't scale well to multi-core systems. Tools like NSOperation were provided to help us write better multi-core code, but GCD was so much more powerful that it completely dominated how multitasking code is written in Cocoa.)
When you subclass NSOperation, you needed to tell the system whether your operation is asynchronous. This isn't a request to run you asynchronously. This is a promise that your start method will not block. It's up to your start method to make sure the operation really is asynchronous.
This is only necessary in the case that your NSOperation is being started manually, and even then it was often not needed. If you put it onto an NSOperationQueue (and you really should always do that), this property is irrelevant. I remember it creating a lot of confusion at the time.
It's become even more irrelevant since the introduction of blocks. It is almost always much easier to use an NSBlockOperation (or dispatch_async) than to subclass NSOperation, which was always a bit tricky to get quite right.
Just in case you haven't already read it, if you want to study Cocoa concurrency, you definitely want to start with the Concurrency Programming Guide.
Asynchronous is always defined relative to the thread that makes a request. So a request is asynchronous relative to thread A if thread A makes a request that runs in thread B such that thread A is able to do other work while thread B is running the request.
If thread B in turn farms out the request to thread C such that thread B is able to do other work while thread C is running the request then that second request is an asynchronous relative to thread B.
It doesn't make sense to just keep farming out the same element of work asynchronously over and over again, of course. But assume the work delegated by thread A to thread B described above can be split up into multiple smaller elements of work. It would be reasonable for thread B to invoke those smaller elements of work asynchronously on threads C, D, etc. This might happen if B provides a service to A such that A doesn't want/need to know the details of how the work gets done; it just wants the work done asynchronously. B knows the details and can decide if/how to accomplish the work via smaller parallel units.
Related
I'm learning about concurrent programming for iOS. So far I've read about NSOperation/NSOperationQueue and GCD. What are the reasons for using NSOperationQueue over GCD and vice versa?
Sounds like both GCD and NSOperationQueue abstract away the explicit creation of NSThreads from the user. However the relationship between the two approaches isn't clear to me so any feedback to appreciated!
GCD is a low-level C-based API that enables very simple use of a task-based concurrency model. NSOperation and NSOperationQueue are Objective-C classes that do a similar thing. NSOperation was introduced first, but as of 10.5 and iOS 2, NSOperationQueue and friends are internally implemented using GCD.
In general, you should use the highest level of abstraction that suits your needs. This means that you should usually use NSOperationQueue instead of GCD, unless you need to do something that NSOperationQueue doesn't support.
Note that NSOperationQueue isn't a "dumbed-down" version of GCD; in fact, there are many things that you can do very simply with NSOperationQueue that take a lot of work with pure GCD. (Examples: bandwidth-constrained queues that only run N operations at a time; establishing dependencies between operations. Both very simple with NSOperation, very difficult with GCD.) Apple's done the hard work of leveraging GCD to create a very nice object-friendly API with NSOperation. Take advantage of their work unless you have a reason not to.
Caveat:
On the other hand, if you really just need to send off a block, and don't need any of the additional functionality that NSOperationQueue provides, there's nothing wrong with using GCD. Just be sure it's the right tool for the job.
In line with my answer to a related question, I'm going to disagree with BJ and suggest you first look at GCD over NSOperation / NSOperationQueue, unless the latter provides something you need that GCD doesn't.
Before GCD, I used a lot of NSOperations / NSOperationQueues within my applications for managing concurrency. However, since I started using GCD on a regular basis, I've almost entirely replaced NSOperations and NSOperationQueues with blocks and dispatch queues. This has come from how I've used both technologies in practice, and from the profiling I've performed on them.
First, there is a nontrivial amount of overhead when using NSOperations and NSOperationQueues. These are Cocoa objects, and they need to be allocated and deallocated. In an iOS application that I wrote which renders a 3-D scene at 60 FPS, I was using NSOperations to encapsulate each rendered frame. When I profiled this, the creation and teardown of these NSOperations was accounting for a significant portion of the CPU cycles in the running application, and was slowing things down. I replaced these with simple blocks and a GCD serial queue, and that overhead disappeared, leading to noticeably better rendering performance. This wasn't the only place where I noticed overhead from using NSOperations, and I've seen this on both Mac and iOS.
Second, there's an elegance to block-based dispatch code that is hard to match when using NSOperations. It's so incredibly convenient to wrap a few lines of code in a block and dispatch it to be performed on a serial or concurrent queue, where creating a custom NSOperation or NSInvocationOperation to do this requires a lot more supporting code. I know that you can use an NSBlockOperation, but you might as well be dispatching something to GCD then. Wrapping this code in blocks inline with related processing in your application leads in my opinion to better code organization than having separate methods or custom NSOperations which encapsulate these tasks.
NSOperations and NSOperationQueues still have very good uses. GCD has no real concept of dependencies, where NSOperationQueues can set up pretty complex dependency graphs. I use NSOperationQueues for this in a handful of cases.
Overall, while I usually advocate for using the highest level of abstraction that accomplishes the task, this is one case where I argue for the lower-level API of GCD. Among the iOS and Mac developers I've talked with about this, the vast majority choose to use GCD over NSOperations unless they are targeting OS versions without support for it (those before iOS 4.0 and Snow Leopard).
GCD is a low-level C-based API.
NSOperation and NSOperationQueue are Objective-C classes.
NSOperationQueue is objective C wrapper over GCD.
If you are using NSOperation, then you are implicitly using Grand Central Dispatch.
GCD advantage over NSOperation:
i. implementation
For GCD implementation is very light-weight
NSOperationQueue is complex and heavy-weight
NSOperation advantages over GCD:
i. Control On Operation
you can Pause, Cancel, Resume an NSOperation
ii. Dependencies
you can set up a dependency between two NSOperations
operation will not started until all of its dependencies return true for finished.
iii. State of Operation
can monitor the state of an operation or operation queue.
ready ,executing or finished
iv. Max Number of Operation
you can specify the maximum number of queued operations that can run simultaneously
When to Go for GCD or NSOperation
when you want more control over queue (all above mentioned) use NSOperation
and for simple cases where you want less overhead
(you just want to do some work "into the background" with very little additional work) use GCD
ref:
https://cocoacasts.com/choosing-between-nsoperation-and-grand-central-dispatch/
http://iosinfopot.blogspot.in/2015/08/nsthread-vs-gcd-vs-nsoperationqueue.html
http://nshipster.com/nsoperation/
Another reason to prefer NSOperation over GCD is the cancelation mechanism of NSOperation. For example, an App like 500px that shows dozens of photos, use NSOperation we can cancel requests of invisible image cells when we scroll table view or collection view, this can greatly improve App performance and reduce memory footprint. GCD can't easily support this.
Also with NSOperation, KVO can be possible.
Here is an article from Eschaton which is worth reading.
GCD is indeed lower-level than NSOperationQueue, its major advantage is that its implementation is very light-weight and focused on lock-free algorithms and performance.
NSOperationQueue does provide facilities that are not available in GCD, but they come at non-trivial cost, the implementation of NSOperationQueue is complex and heavy-weight, involves a lot of locking, and uses GCD internally only in a very minimal fashion.
If you need the facilities provided by NSOperationQueue by all means use it, but if GCD is sufficient for your needs, I would recommend using it directly for better performance, significantly lower CPU and power cost and more flexibility.
Both NSQueueOperations and GCD allow executing heavy computation task in the background on separate threads by freeing the UI Application Main Tread.
Well, based previous post we see NSOperations has addDependency so that you can queue your operation one after another sequentially.
But I also read about GCD serial Queues you can create run your operations in the queue using dispatch_queue_create. This will allow running a set of operations one after another in a sequential manner.
NSQueueOperation Advantages over GCD:
It allows to add dependency and allows you to remove dependency so for one transaction you can run sequential using dependency and for other transaction run concurrently while GCD
doesn't allow to run this way.
It is easy to cancel an operation if it is in the queue it can be stopped if it is running.
You can define the maximum number of concurrent operations.
You can suspend operation which they are in Queue
You can find how many pending operations are there in queue.
GCD is very easy to use - if you want to do something in the background, all you need to do is write the code and dispatch it on a background queue. Doing the same thing with NSOperation is a lot of additional work.
The advantage of NSOperation is that (a) you have a real object that you can send messages to, and (b) that you can cancel an NSOperation. That's not trivial. You need to subclass NSOperation, you have to write your code correctly so that cancellation and correctly finishing a task both work correctly. So for simple things you use GCD, and for more complicated things you create a subclass of NSOperation. (There are subclasses NSInvocationOperation and NSBlockOperation, but everything they do is easier done with GCD, so there is no good reason to use them).
Well, NSOperations are simply an API built on top of Grand Central Dispatch. So when you’re using NSOperations, you’re really still using Grand Central Dispatch.
It’s just that NSOperations give you some fancy features that you might like. You can make some operations dependent on other operations, reorder queues after you sumbit items, and other things like that.
In fact, ImageGrabber is already using NSOperations and operation queues! ASIHTTPRequest uses them under the hood, and you can configure the operation queue it uses for different behavior if you’d like.
So which should you use? Whichever makes sense for your app. For this app it’s pretty simple so we just used Grand Central Dispatch directly, no need for the fancy features of NSOperation. But if you need them for your app, feel free to use it!
I agree with #Sangram and other answers but want to add few points. Correct me if I am wrong.
I think now a days first two points of #Sangram's answer are not valid (i. Control On Operation ii. Dependencies). We can achieve these two by using GCD also. Trying to explain by code(do not focus on quality of code, this is for reference purpose only)
func methodsOfGCD() {
let concurrentQueue = DispatchQueue.init(label: "MyQueue", qos: .background, attributes: .concurrent)
//We can suspend and resume Like this
concurrentQueue.suspend()
concurrentQueue.resume()
//We can cancel using DispatchWorkItem
let workItem = DispatchWorkItem {
print("Do something")
}
concurrentQueue.async(execute: workItem)
workItem.cancel()
//Cam add dependency like this.
//Operation 1
concurrentQueue.async(flags: .barrier) {
print("Operation1")
}
//Operation 2
concurrentQueue.async(flags: .barrier) {
print("Operation2")
}
//Operation 3.
//Operation 3 have dependency on Operation1 and Operation2. Once 1 and 2 will finish will execute Operation 3. Here operation queue work as a serial queue.
concurrentQueue.async(flags: .barrier) {
print("Operation3")
}
}
This question already has answers here:
Use of the terms "queues", "multicore", and "threads" in Grand Central Dispatch
(3 answers)
Closed 8 years ago.
I am new to iOS development. Now I am quite confused about the two concepts: "thread" and "queue". All I know is that they both are about multithread programming. Can anyone interpret those two concepts and the difference between them for me?
Thanks in advance!
How NSOperationQueue and NSThread Works:
NSThread:
iOS developers have to write code for the work/process he want to perform along with for the creation and management of the threads themselves.
iOS developers have to be careful about a plan of action for using threads.
iOS developer have to manage posiable problems like reuseability of thread, lockings etc. by them self.
Thread will consume more memory too.
NSOperationQueue:
The NSOperation class is an abstract class which encapsulates the code and data associated with a single task.
Developer needs to use subclass or one of the system-defined subclasses of NSOperation to perform the task.
Add operations into NSOperationQueue to execute them.
The NSOperationQueue creates a new thread for each operation and runs them in the order they are added.
Operation queues handle all of the thread management, ensuring that operations are executed as quickly and efficiently as possible.
An operation queue executes operations either directly by running them on secondary threads or indirectly using GCD (Grand Central Dispatch).
It takes care of all of the memory management and greatly simplifies the process.
If you don’t want to use an operation queue, you can also execute an operation by calling its start method. It may make your code too complex.
How To Use NSThread And NSOperationQueue:
NSThread:
Though Operation queues is the preferred way to perform tasks concurrently, depending on application there may still be times when you need to create custom threads.
Threads are still a good way to implement code that must run in real time.
Use threads for specific tasks that cannot be implemented in any other way.
If you need more predictable behavior from code running in the background, threads may still offer a better alternative.
NSOperationQueue:
Use NSOperationQueue when you have more complex operations you want to run concurrently.
NSOperation allows for subclassing, dependencies, priorities, cancellation and a supports a number of other higher-level features.
NSOperation actually uses GCD under the hood so it is as multi-core, multi-thread capable as GCD.
Now you should aware about advantages and disadvantages of NSTread and NSOperation. You can use either of them as per needs of your application.
Before you read my answer you might want to consider reading this - Migrating away from Threads
I am keeping the discussion theoretical as your question does not have any code samples. Both these constructs are required for increasing app responsiveness & usability.
A message queue is a data structure for holding messages from the time they're sent until the time the receiver retrieves and acts on them. Generally queues are used as a way to 'connect' producers (of data) & consumers (of data).
A thread pool is a pool of threads that do some sort of processing. A thread pool will normally have some sort of thread-safe queue (refer message queue) attached to allow you to queue up jobs to be done. Here the queue would usually be termed 'task-queue'.
So in a way thread pool could exist at your producer end (generating data) or consumer end (processing the data). And the way to 'pass' that data would be through queues. Why the need for this "middleman" -
It decouples the systems. Producers do not know about consumers & vice versa.
The Consumers are not bombarded with data if there is a spike in Producer data. The queue length would increase but the consumers are safe.
Example:
In iOS the main thread, also called the UI thread, is very important because it is in charge of dispatching the events to the appropriate widget and this includes the drawing events, basically the UI that the user sees & interacts.
If you touch a button on screen, the UI thread dispatches the touch event to the app, which in turn sets its pressed state and posts an request to the event queue. The UI thread dequeues the request and notifies the widget to redraw itself.
I'm developing a sort of fast image scan application.
In the -captureOutput:didOutputSampleBuffer:fromConnection: method I pick up the CVPixelBuffer and add them into an NSOperation subclass. The NSOperation takes the buffer and transform it into an image saved on the filesystem.
The -isConcurrent method of NSOperation returns YES. After the operation is created, is added to an NSOperationQueue.
Everything runs fine except for one issue that is affecting the scan frame rate.
Using time profiler I've found that some of the NSOperation are run on the same thread of the AVCaputureVideoOutput delegate that I've created:
dispatch_queue_t queue = dispatch_queue_create("it.CloudInTouchLabs.avsession", DISPATCH_QUEUE_SERIAL);
[dataOutput setSampleBufferDelegate:(id)self queue:queue];
When an operation is running on the same thread of the AV session queue, it affects the frame rate, it happens only with some them, probably GCD is deciding under the hood dispatching on active threads. The only method I've found to solve that issue, is to create a separate thread and pass it to the the single operations forcing them to run on it.
Is there another way, to force operations run on a different thread?
[EDIT]
Following the #impcc suggestions I made some test.
Results are pretty interesting even if sort of inconsistent.
Test platform is an iPhone 5 connected in debugging mode through an MBP with 16gb of RAM quad core i7. The session has a 60fps output tested with the algorithm in RosyWriter apple sample code.
AVSession queue sync targeted to high priority queue
26 fps where sometimes the thread of the queue is shared with the one
of the operation. The time taken inside the delegate methods has an
average of 0.02s
14 fps with a thread created just for the operations, if the main
method is not called on this thread, the start will be forced to perform
on that specific thread. This thread is create one time and kept
alive with a dummy port.. The time taken inside the delegate is
0.008.
AVSession queue concurrent targeted to high priority queue
13.5 fps where sometimes the thread of the queue is shared with the one of the operation. The time taken inside the delegate methods has
an average of 0.02s, substacially equal to the counterpart with sync
queue.
14 fps with a thread created just for the operations, if the main
method is not called on this thread, the start will be forced to perform
on that specific thread. This thread is create one time and kept
alive with a dummy port. The time taken inside the delegate is
0.008.
Conclusion
Concurrent or serial queue doesn't seems to make a big difference, however concurrent for me is not ok cause of the timestamps that I need to take to preserve the sequence of single picture. The fact that is surprising me is the frame drop using an ad-hoc thread, even if the time taken inside the delegate method is considerably less, the frame rate drops about 10fps. Just trusting in GCD the frame rate is better but the delegate methods takes more than 2 times to finish, this probably due to the fact that sometimes the AV queue is used by also the nsoperations. I can't really get why the time taken inside the delegate doesn't seems to be correlated to the fps. Shouldn't be the faster the better?
By further investigations it really seems that what is stealing time si in the process of adding and probably executing operation in queue.
I think you might be misunderstanding the meaning of isConcurrent. This is totally understandable, since it's incredibly poorly named. When you return YES from -isConcurrent what it really means is "I will handle any concurrency needs associated with this operation, and will otherwise behave asynchronously." In this situation, NSOperationQueue is free to call -start on your operation synchronously on the thread from which you add the operation. The NSOperationQueue is expecting that, because you've declared that you will manage your own concurrency, that your -start method will simply kick off an asynchronous process and return right away. I suspect this is the source of your problem.
If you implemented your operation by overriding -main then you almost certainly want to be returning NO from isConcurrent. To make matters more complicated, the behaviors associated with isConcurrent have changed over the years (but all that is covered in the official docs.) A fantastic explanation of how to properly implement a returns-YES-from-isConcurrent NSOperation can be found here.
The way I'm reading your question here, it doesn't sound like your NSOperation subclass actually needs to "manage its own concurrency", but rather that you simply want it to execute asynchronously, "on a background thread", potentially "concurrently" with other operations.
In terms of assuring the best performance for your AVCaptureVideoDataOutputSampleBufferDelegate callbacks, I would suggest making the queue you pass in to -setSampleBufferDelegate:queue: be (itself) concurrent and that it target the high-priority global concurrent queue, like this:
dispatch_queue_t queue = dispatch_queue_create("it.CloudInTouchLabs.avsession", DISPATCH_QUEUE_CONCURRENT);
dispatch_set_target_queue(queue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0));
[dataOutput setSampleBufferDelegate:(id)self queue:queue];
Then you should make the delegate callback methods as lightweight as possible -- nothing more than packaging up the information you need to make the NSOperation and add it to the NSOperationQueue.
This should ensure that the callbacks always take precedence over the NSOperations. (It's my understanding that NSOperationQueue targets either the main queue (for the NSOperationQueue that's associated with the main thread and run loop) or the default priority background queue.) This should allow your callbacks to fully keep up with the frame rate.
Another important thing to take away here (that another commenter was getting at) is that if you're doing all your concurrency using GCD, then there is only one special thread -- the main thread. Other than that, threads are just a generic resource that GCD can (and will) use interchangeably with one another. The fact that a thread with a thread ID of X was used at one point to service your delegate callback, and at another point was used to do your processing is not, in and of itself, indicative of a problem.
Hope this helps!
I'm learning about concurrent programming for iOS. So far I've read about NSOperation/NSOperationQueue and GCD. What are the reasons for using NSOperationQueue over GCD and vice versa?
Sounds like both GCD and NSOperationQueue abstract away the explicit creation of NSThreads from the user. However the relationship between the two approaches isn't clear to me so any feedback to appreciated!
GCD is a low-level C-based API that enables very simple use of a task-based concurrency model. NSOperation and NSOperationQueue are Objective-C classes that do a similar thing. NSOperation was introduced first, but as of 10.5 and iOS 2, NSOperationQueue and friends are internally implemented using GCD.
In general, you should use the highest level of abstraction that suits your needs. This means that you should usually use NSOperationQueue instead of GCD, unless you need to do something that NSOperationQueue doesn't support.
Note that NSOperationQueue isn't a "dumbed-down" version of GCD; in fact, there are many things that you can do very simply with NSOperationQueue that take a lot of work with pure GCD. (Examples: bandwidth-constrained queues that only run N operations at a time; establishing dependencies between operations. Both very simple with NSOperation, very difficult with GCD.) Apple's done the hard work of leveraging GCD to create a very nice object-friendly API with NSOperation. Take advantage of their work unless you have a reason not to.
Caveat:
On the other hand, if you really just need to send off a block, and don't need any of the additional functionality that NSOperationQueue provides, there's nothing wrong with using GCD. Just be sure it's the right tool for the job.
In line with my answer to a related question, I'm going to disagree with BJ and suggest you first look at GCD over NSOperation / NSOperationQueue, unless the latter provides something you need that GCD doesn't.
Before GCD, I used a lot of NSOperations / NSOperationQueues within my applications for managing concurrency. However, since I started using GCD on a regular basis, I've almost entirely replaced NSOperations and NSOperationQueues with blocks and dispatch queues. This has come from how I've used both technologies in practice, and from the profiling I've performed on them.
First, there is a nontrivial amount of overhead when using NSOperations and NSOperationQueues. These are Cocoa objects, and they need to be allocated and deallocated. In an iOS application that I wrote which renders a 3-D scene at 60 FPS, I was using NSOperations to encapsulate each rendered frame. When I profiled this, the creation and teardown of these NSOperations was accounting for a significant portion of the CPU cycles in the running application, and was slowing things down. I replaced these with simple blocks and a GCD serial queue, and that overhead disappeared, leading to noticeably better rendering performance. This wasn't the only place where I noticed overhead from using NSOperations, and I've seen this on both Mac and iOS.
Second, there's an elegance to block-based dispatch code that is hard to match when using NSOperations. It's so incredibly convenient to wrap a few lines of code in a block and dispatch it to be performed on a serial or concurrent queue, where creating a custom NSOperation or NSInvocationOperation to do this requires a lot more supporting code. I know that you can use an NSBlockOperation, but you might as well be dispatching something to GCD then. Wrapping this code in blocks inline with related processing in your application leads in my opinion to better code organization than having separate methods or custom NSOperations which encapsulate these tasks.
NSOperations and NSOperationQueues still have very good uses. GCD has no real concept of dependencies, where NSOperationQueues can set up pretty complex dependency graphs. I use NSOperationQueues for this in a handful of cases.
Overall, while I usually advocate for using the highest level of abstraction that accomplishes the task, this is one case where I argue for the lower-level API of GCD. Among the iOS and Mac developers I've talked with about this, the vast majority choose to use GCD over NSOperations unless they are targeting OS versions without support for it (those before iOS 4.0 and Snow Leopard).
GCD is a low-level C-based API.
NSOperation and NSOperationQueue are Objective-C classes.
NSOperationQueue is objective C wrapper over GCD.
If you are using NSOperation, then you are implicitly using Grand Central Dispatch.
GCD advantage over NSOperation:
i. implementation
For GCD implementation is very light-weight
NSOperationQueue is complex and heavy-weight
NSOperation advantages over GCD:
i. Control On Operation
you can Pause, Cancel, Resume an NSOperation
ii. Dependencies
you can set up a dependency between two NSOperations
operation will not started until all of its dependencies return true for finished.
iii. State of Operation
can monitor the state of an operation or operation queue.
ready ,executing or finished
iv. Max Number of Operation
you can specify the maximum number of queued operations that can run simultaneously
When to Go for GCD or NSOperation
when you want more control over queue (all above mentioned) use NSOperation
and for simple cases where you want less overhead
(you just want to do some work "into the background" with very little additional work) use GCD
ref:
https://cocoacasts.com/choosing-between-nsoperation-and-grand-central-dispatch/
http://iosinfopot.blogspot.in/2015/08/nsthread-vs-gcd-vs-nsoperationqueue.html
http://nshipster.com/nsoperation/
Another reason to prefer NSOperation over GCD is the cancelation mechanism of NSOperation. For example, an App like 500px that shows dozens of photos, use NSOperation we can cancel requests of invisible image cells when we scroll table view or collection view, this can greatly improve App performance and reduce memory footprint. GCD can't easily support this.
Also with NSOperation, KVO can be possible.
Here is an article from Eschaton which is worth reading.
GCD is indeed lower-level than NSOperationQueue, its major advantage is that its implementation is very light-weight and focused on lock-free algorithms and performance.
NSOperationQueue does provide facilities that are not available in GCD, but they come at non-trivial cost, the implementation of NSOperationQueue is complex and heavy-weight, involves a lot of locking, and uses GCD internally only in a very minimal fashion.
If you need the facilities provided by NSOperationQueue by all means use it, but if GCD is sufficient for your needs, I would recommend using it directly for better performance, significantly lower CPU and power cost and more flexibility.
Both NSQueueOperations and GCD allow executing heavy computation task in the background on separate threads by freeing the UI Application Main Tread.
Well, based previous post we see NSOperations has addDependency so that you can queue your operation one after another sequentially.
But I also read about GCD serial Queues you can create run your operations in the queue using dispatch_queue_create. This will allow running a set of operations one after another in a sequential manner.
NSQueueOperation Advantages over GCD:
It allows to add dependency and allows you to remove dependency so for one transaction you can run sequential using dependency and for other transaction run concurrently while GCD
doesn't allow to run this way.
It is easy to cancel an operation if it is in the queue it can be stopped if it is running.
You can define the maximum number of concurrent operations.
You can suspend operation which they are in Queue
You can find how many pending operations are there in queue.
GCD is very easy to use - if you want to do something in the background, all you need to do is write the code and dispatch it on a background queue. Doing the same thing with NSOperation is a lot of additional work.
The advantage of NSOperation is that (a) you have a real object that you can send messages to, and (b) that you can cancel an NSOperation. That's not trivial. You need to subclass NSOperation, you have to write your code correctly so that cancellation and correctly finishing a task both work correctly. So for simple things you use GCD, and for more complicated things you create a subclass of NSOperation. (There are subclasses NSInvocationOperation and NSBlockOperation, but everything they do is easier done with GCD, so there is no good reason to use them).
Well, NSOperations are simply an API built on top of Grand Central Dispatch. So when you’re using NSOperations, you’re really still using Grand Central Dispatch.
It’s just that NSOperations give you some fancy features that you might like. You can make some operations dependent on other operations, reorder queues after you sumbit items, and other things like that.
In fact, ImageGrabber is already using NSOperations and operation queues! ASIHTTPRequest uses them under the hood, and you can configure the operation queue it uses for different behavior if you’d like.
So which should you use? Whichever makes sense for your app. For this app it’s pretty simple so we just used Grand Central Dispatch directly, no need for the fancy features of NSOperation. But if you need them for your app, feel free to use it!
I agree with #Sangram and other answers but want to add few points. Correct me if I am wrong.
I think now a days first two points of #Sangram's answer are not valid (i. Control On Operation ii. Dependencies). We can achieve these two by using GCD also. Trying to explain by code(do not focus on quality of code, this is for reference purpose only)
func methodsOfGCD() {
let concurrentQueue = DispatchQueue.init(label: "MyQueue", qos: .background, attributes: .concurrent)
//We can suspend and resume Like this
concurrentQueue.suspend()
concurrentQueue.resume()
//We can cancel using DispatchWorkItem
let workItem = DispatchWorkItem {
print("Do something")
}
concurrentQueue.async(execute: workItem)
workItem.cancel()
//Cam add dependency like this.
//Operation 1
concurrentQueue.async(flags: .barrier) {
print("Operation1")
}
//Operation 2
concurrentQueue.async(flags: .barrier) {
print("Operation2")
}
//Operation 3.
//Operation 3 have dependency on Operation1 and Operation2. Once 1 and 2 will finish will execute Operation 3. Here operation queue work as a serial queue.
concurrentQueue.async(flags: .barrier) {
print("Operation3")
}
}
I have an app where I'm downloading a number of resources from the network, and doing some processing on each one. I don't want this work happening on the main thread, but it's pretty lightweight and low-priority, so all of it can really happen on the same shared work thread. That seems like it'd be a good thing to do, because of the work required to set up & tear down all of these work threads (none of which will live very long, etc.).
Surprisingly, though, there doesn't seem to be a simple way to get all of this work happening on a single, shared thread, rather than spawning a new thread for each task. This is complicated by the large number of paths to achieving concurrency that seem to have cropped up over the years. (Explicit NSThreads, NSOperationQueue, GCD, etc.)
Am I over-estimating the overhead involved in spawning all of these threads? Should I just not sweat it, and use the easier thread-per-task approaches? Use GCD, and assume that it's smarter than I about thread (re)use?
Use GCD — it's the current official recommendation and it's less effort than any of the other solutions. If you explicitly need the things you pass in to occur serially (ie, as if on a single thread) then you can achieve that but it's probably smarter just to change, e.g.
[self doCostlyTask];
To:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^()
{
[self doCostlyTask];
dispatch_async(dispatch_get_main_queue(), ^()
{
// most UIKit tasks are permissible only from the main queue or thread,
// so if you want to update an UI as a result of the completed action,
// this is a safe way to proceed
[self costlyTaskIsFinished];
});
});
That essentially tells the OS "do this code with low priority wherever it would be most efficient to do it". The various things you post to any of the global queues may or may not execute on the same thread as each other and as the thread that dispatched them and may or may not occur concurrently. The OS applies the rules it considers optimal.
Exposition:
GCD is Apple's implementation of thread pooling, and they introduced closures (as 'blocks') at the same time to make it usable. So the ^(C-style args){code} syntax is a block/closure. That is, it's code plus the state of any variables (subject to caveats) that the code references. You can store and call blocks yourself with no GCD knowledge or use.
dispatch_async is a GCD function issues a block to the nominated queue. It executes the block on some thread at some time, and applies unspecified internal rules to do so in an optimal fashion. It'll judge that based on factors such as how many cores you have, how busy each is, what it's currently thinking on power saving (which may depend on power source), how the power costs for that specific CPU work out, etc.
So as far as the programmer is developed, blocks make code into something you can pass around as an argument. GCD lets you request that blocks are executed according to the best scheduling the OS can manage. Blocks are very lightweight to create and copy — a lot more so than e.g. NSOperations.
GCD goes beyond the basic asynchronous dispatch in the above example (eg, you can do a parallel for loop and wait for it to finish in a single call) but unless you have specific needs it's probably not all that relevant.
Surprisingly, though, there doesn't seem to be a simple way to get all
of this work happening on a single, shared thread, rather than
spawning a new thread for each task.
This is exactly what GCD is for. GCD maintains a pool of threads that can be used for executing arbitrary blocks of code, and it takes care of managing that pool for best results on whatever hardware is at hand. This avoids the cost of constantly creating and destroying threads and also saves you from having to figure out how many processors are available, etc.
Tommy provides the right answer if you really care that only a single thread should be used, but it sounds like you're really just trying to avoid creating one thread per task.
This is complicated by the large number of paths to achieving
concurrency that seem to have cropped up over the years. (Explicit
NSThreads, NSOperationQueue, GCD, etc.)
NSOperationQueue uses GCD, so you can use that if it makes life easier than using GCD directly.
Use GCD, and assume that it's smarter than I about thread (re)use?
Exactly.
I would use NSOperationQueue or GCD and profile. Can't imagine thread overhead will beat out network delays.
NSOperationQueue would let you limit the number of simultaneous operations, if they end up getting too greedy. In fact, you can limit it to one if you need to.