How to programmatically manage and balance the number of applications running iOS?

How to control and balance the number of threads executed by my application, how to limit their number to avoid blocking applications, because the thread limit is reached?

Here on SO, I saw the following possible answer: "The main parallel queue (dispatch_get_global_queue) controls the number of threads automatically", which I don't like for the following reason:

Consider the following pattern (in my real application there are simpler and more complex examples):

dispatch_queue_t defaultBackgroundQueue() { return dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); } dispatch_queue_t databaseQueue() { dispatch_queue_create("Database private queue", 0); } dispatch_async(defaultBackgroundQueue(), ^{ [AFNetworkingAsynchronousRequestWithCompletionHandler:^(data){ dispatch_async(databaseQueue(), ^{ // data is about 100-200 elements to parse for (el in data) { } maybe more AFNetworking requests and/or processing in other queues or dispatch_async(dispatch_get_main_queue(), ^{ // At last! We can do something on UI. }); }); }]; }); 

This scheme very often leads to a situation when:

  • The application is blocked due to the thread limit being reached (something like> 64).
  • slower and therefore narrower queues can be overloaded with a large number of pending jobs.
  • the second can also cause a cancellation problem - if we have 100 jobs that are already waiting to be completed in a sequential queue, we cannot immediately cancel them.

An obvious and dumb solution would be to replace sensitive dispatch_async methods with dispatch_sync, but this is definitely one that I don't like.

What approach is recommended for such situations?

I hope the answer is smarter than just “Use NSOperationQueue - it can limit the number of concurrent operations” (similar topic: Number of threads with NSOperationQueueDefaultMaxConcurrentOperationCount ).

UPDATE 1: the only decent template: replace all dispatch_async blocks with parallel queues with the launch of these blocks wrapped in NSOperations in parallel queues based on NSOperationQueue with the maximum set of maximum operations (in my case, you can also set the max limit of operations in the NSOperationQueue queue in which AFNetworking performs all its operations).

+4
source share
2 answers

You are running too many network requests. AFAIK is not documented anywhere, but you can run up to 6 simultaneous network connections (which is a reasonable number considering RFC 2616 8.1.4 , paragraph 6). After that, you get a lock, and GCD compensates for the creation of more threads, which, incidentally, have a stack space of 512 KB each with pages allocated on request. So yes, use NSOperation for this. I use it to queue network requests, increase priority, when the same object is requested again, it pauses and serializes to disk if the user leaves. I also track the speed of network requests in bytes / time and change the number of concurrent operations.

+7
source

Until I see in your example where exactly you create “too many” background threads, I’ll just try to answer the question of how to control the exact number of threads in the queue. Apple documentation says:

Parallel queues (also known as the global dispatch queue type) perform one or more tasks at the same time, but the tasks still start in the order in which they were added to the queue. Currently performed tasks are performed in different threads, which are controlled by the send queue. The exact number of tasks performed at any given point is variable and depends on system conditions.

While you can (starting from iOS5) create parallel queues manually, there is no way to control how many tasks will be performed simultaneously with such a queue. The OS will automatically balance the load. If for some reason you do not want this, you can, for example, create a set of consecutive queues of n manually and send new jobs to one of your n queues in a random manner:

 NSArray *queues = @[dispatch_queue_create("com.myapp.queue1", 0),dispatch_queue_create("com.myapp.queue2", 0),dispatch_queue_create("com.myapp.queue3", 0)]; NSUInteger randQueue = arc4random() % [queues count]; dispatch_async([queues objectAtIndex:randQueue], ^{ NSLog(@"Do something"); }); randQueue = arc4random() % [queues count]; dispatch_async([queues objectAtIndex:randQueue], ^{ NSLog(@"Do something else"); }); 

I do not endorse this design in any way - I think parallel queues are pretty good at balancing system resources. But since you asked, I think this is an acceptable approach.

+1
source

All Articles