Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

With NSOperationQueue, how do you add to a background queue instead of main, and how does controlling amount of operations work?

I'm loving NSOperationQueue but I'm having some issues understanding some portions of it.

In the second issue of objc.io they go over NSOperationQueue and mention that it has two kinds of queues, the main queue which runs on the main thread, and the background queues. They mention you can access the main queue with [NSOperation mainQueue] and then add manipulate it.

  • You normally would not want to do this, correct? If it's running on the main thread, will it not block the main thread for other tasks? Wouldn't it not run concurrently with other tasks?

It also mentions you can add to the background queues (which I understand would be better?) by creating instances of NSOperation (subclasses potentially).

  • Do I save a reference to the NSOperationQueue that I create for operations in order to have for creating more operations? I assume there's no singleton for background queues like there is for mainQueue, so how do I manage adding tasks to background queues?

It also mentions you can control the amount of operations running concurrently with the maxConcurrentOperationCount property.

  • I know normally you set it to NSOperationQueueDefaultMaxConcurrentOperationCount, but if I set it to a specific number manually, does it correspond to the maximum number of threads that can be run at once? For example if the processor on the iPhone can run 4 threads at once and I set that property to 8, what happens?
like image 837
Doug Smith Avatar asked Jan 13 '14 16:01

Doug Smith


1 Answers

You ask:

You normally would not want [to add operations to the mainQueue], correct? If it's running on the main thread, will it not block the main thread for other tasks? Wouldn't it not run concurrently with other tasks?

Yes, you would never want to add anything slow to the main queue. But that doesn't mean that you don't use the main queue. For some operations (e.g. UI updates) it's critical.

The typical pattern is to create a operation queue for tasks that you want to run in the background, but if you subsequently need to do something that needs to run on the main queue (e.g. UI updates, updating the model, etc.), you would go ahead and do that, for example:

NSOperationQueue *queue = [[NSOperationQueue alloc] init];

[queue addOperationWithBlock:^{
    // do some time consuming stuff in the background

    // when done, you might update the UI in the main queue

    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        // update the UI here
    }];
];

You ask:

Do I save a reference to the NSOperationQueue that I create for operations in order to have for creating more operations? I assume there's no singleton for background queues like there is for mainQueue, so how do I manage adding tasks to background queues?

Yes, if you want to add more operations to that same queue later, yes, you want to maintain a reference to that queue. You can do this by adding it to the app delegate, some central view controller, or a singleton.

But yes, there's no built-in singleton for background queues (because you can, conceivably have different queues for different operations, e.g. one for network operations, one for image processing, etc.). But you can write your own singleton for each queue of each type, if you want.

You also ask:

I know normally you set it to NSOperationQueueDefaultMaxConcurrentOperationCount, but if I set it to a specific number manually, does it correspond to the maximum number of threads that can be run at once? For example if the processor on the iPhone can run 4 threads at once and I set that property to 8, what happens?

One should set maxConcurrentOperationCount to be whatever you think is appropriate for the type of queue. For network operation queue, you generally wouldn't exceed 4, but for other types of queues, you might easily have more. I believe that there is a maximum of 64 worker threads (which concurrent queues avail themselves as they need threads).

If you attempt to use more than that, the app won't start your operation until a worker thread becomes available. Apple advises, though, that one refrain from using up all of the worker threads. So use a reasonable number appropriate for your queue's function. Frankly, one of the advantages of operation queues over dispatch queues is that you can constrain the maximum number of worker threads that will be used at any given time to better manage the device's limited resources.


References

  • WWDC 2012 video Asynchronous Design Patterns with Blocks, GCD, and XPC is an excellent primer on some GCD patterns and touches upon the "too many threads" question.

  • The Building Concurrent User Interfaces on iOS video walks through some practical implications of building concurrent iOS apps.

  • The About Threaded Programming section of the Threading Programming Guide touches upon the relationship between cores and threads.

  • The Concurrency and Application Design section of the Concurrency Programming Guide is an articulate discussion of the relationships between threads and operation/dispatch queues.

like image 80
Rob Avatar answered Oct 04 '22 08:10

Rob