Why should I choose GCD over NSOperation and blocks for high-level applications?

17,748

Solution 1

The point being made here is the same one that Chris Hanson states in his article "When to use NSOperation vs. GCD":

The straightforward answer is a general guideline for all application development:

Always use the highest-level abstraction available to you, and drop down to lower-level abstractions when measurement shows that they are needed.

In this particular case, it means that when writing Cocoa applications, you should generally be using NSOperation rather than using GCD directly. Not because of a difference in efficiency, but because NSOperation provides a higher-level abstraction atop the mechanisms of GCD.

In general, I agree with this. NSOperation and NSOperationQueue provide support for dependencies and one or two other things that GCD blocks and queues don't have, and they abstract away the lower-level details of how the concurrent operations are implemented. If you need that functionality, NSOperation is a very good way to go.

However, after working with both, I've found myself replacing all of my NSOperation-based code with GCD blocks and queues. I've done this for two reasons: there is significant overhead when using NSOperation for frequent actions, and I believe my code is cleaner and more descriptive when using GCD blocks.

The first reason comes from profiling in my applications, where I found that the NSOperation object allocation and deallocation process took a significant amount of CPU resources when dealing with small and frequent actions, like rendering an OpenGL ES frame to the screen. GCD blocks completely eliminated that overhead, leading to significant performance improvements.

The second reason is more subjective, but I believe that my code is cleaner when using blocks than NSOperations. The quick capture of scope allowed by a block and the inline nature of them make for less code, because you don't need to create custom NSOperation subclasses or bundle up parameters to be passed into the operation, and more descriptive code in my opinion, because you can place the code to be run in a queue at the point where it is fired off.

Again, its a matter of preference, but I've found myself using GCD more, even in otherwise more abstracted Cocoa applications.

Solution 2

  • Prefer GCD where task is not much complex and optimum CPU performance is required.
  • Prefer NSOperationQueue where task is complex and requires canceling or suspending a block and dependency management.

GCD is a lightweight way to represent units of work that are going to be executed concurrently. You don’t schedule these units of work; the system takes care of scheduling for you. Adding dependency among blocks can be a headache. Canceling or suspending a block creates extra work for you as a developer!

NSOperation and NSOperationQueue add a little extra overhead compared to GCD, but you can add dependency among various operations. You can re-use, cancel or suspend operations. NSOperation is compatible with Key-Value Observation (KVO); for example, you can have an NSOperation start running by listening to NSNotificationCenter.

For detailed explanation, refer this question: NSOperation vs Grand Central Dispatch

Solution 3

Well, NSOperation has no equivalents to dispatch_source_t, dispatch_io, dispatch_data_t, dispatch_semaphore_t, etc... It's also somewhat higher overhead.

On the flip side, libdispatch has no equivalents to operation dependencies, operation priorities (queue priorities are somewhat different), or KVO on operations.

Solution 4

There are two things that NSOperationQueue can do that GCD doesn't do: The minor one is dependencies (add an operation to a queue but tell it to only execute when certain other operations are finished), and the big one is that NSOperation gives you an object which can receive messages while the task is executing, unlike GCD which has blocks that cannot receive messages except in a very limited way. You either need these two features, or you don't. If you don't, using GCD is just an awful lot easier to use.

That's why useful examples of NSOperation are always quite complex. If they were easy, you would use GCD instead. You usually create a subclass of NSOperation, which will be some significant amount of work, or use one that someone else has created.

Share:
17,748
Lio
Author by

Lio

Updated on July 14, 2022

Comments

  • Lio
    Lio almost 2 years

    Apple's Grand Central Dispatch reference says:

    "...if your application needs to operate at the Unix level of the system—for example, if it needs to manipulate file descriptors, Mach ports, signals, or timers. GCD is not restricted to system-level applications, but before you use it for higher-level applications, you should consider whether similar functionality provided in Cocoa (via NSOperation and block objects) would be easier to use or more appropriate for your needs.".

    http://developer.apple.com/library/ios/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html

    I can't actually think of situations, for high-level applications, in which the use of GCD is mandatory and NSOperation could/should not be used.

    Any thoughts?

  • hypercrypt
    hypercrypt over 12 years
    NSOperation is now built on top of GCD, so unless there is something in one that you need that isn't in the other there is not that much in favour over the other.
  • Catfish_Man
    Catfish_Man over 12 years
    It still requires object allocations for operations, among other complexities. For extremely fine-grained threading that can actually be a meaningful overhead. Yes, I have measured this; yes it is critical for some of my code. NSOperation's wrapping of GCD is not at all the straightforward mapping one might expect, since it needs to support dependencies, KVO, and priorities.
  • Brad Larson
    Brad Larson over 12 years
    He's right, I've also seen significant overhead in using NSOperation for frequently occurring actions where I don't see that with GCD blocks. Object allocation / deallocation can be very expensive in those cases, so GCD may be more appropriate.
  • Hayden Holligan
    Hayden Holligan over 7 years
    NSOperationQueue is capable of using closures now. Should this answer be (slightly) updated? Also, is there any chance that NSOperation has been optimized in the past 5 years to reduce the overhead you found?
  • strangetimes
    strangetimes over 7 years
    I should add that I've ended up doing the exact opposite - after years of using GCD directly, switching over to NSOperationQueue was a breath of fresh air. My 'queueing' behaviour is well defined now, and I have full control over the max concurrent operations. Cancelling running operations and replacing them with new ones is also easier, resulting in well defined behaviour. I still use GCD for simple async operations, but I've switched to NSOperationQueue for my serial / async queueing needs.
  • l --marc l
    l --marc l almost 4 years
    Also, from a 2020 Swift perspective, Operation & OperationQueue are type NSObject (Objective-C heritage) while DispatchQueue, DispatchWorkItem & DispatchGroup are not.