0

If an iOS app has to make hundreds of server requests in background and save the result in local mobile database, which approach would be better in terms of performance (less crashes)?

Passing all requests as 1 block in Global Background Queue

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
    for (i=0;i<users;i++)
      {
        Call Api 1
        Call Api 2
        Call Api 3
      }
});

OR

Creating 'n' number of User Serial Queues and adding all 3 api calls as individual blocks in each serial queue.

for (i=0;i<users;i++)
{
    dispatch_queue_t myQueue = dispatch_queue_create([[users objectAtIndex:i] UTF8String], DISPATCH_QUEUE_SERIAL);
              dispatch_async(myQueue, ^{
                   Call Api 1
                });
              dispatch_async(myQueue, ^{
                   Call Api 2
                });
              dispatch_async(myQueue, ^{
                   Call Api 3
                });
}

Edit: In each Call Api, I am using NSOperationQueue.

queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {..}

2 Answers2

2

I would suggest using NSOperations rather. Create 'n' NSOperations one for each API. Create a NSOperatioQueue, add the NSOperations to queue and sit back and relax while iOS takes the burden of deciding how many operations to run concurrently and all other complicated task ascociated with thread and memory for you :)

The major difference between GCD and NSOperations is the ability to pause and resume the operations :) In case of GCD once submitted operation is bound to happen and there is no way you can skip them or pause them :)

Adding the dependencies between multiple operations in GCD is cumbersome where as adding dependencies and prioritising tasks in NSOperations is just a matter of few statements :)

EDIT

As per your edit you are already using NSOperation for each API. So there is absolutely no need to call the NSOperations in dispatch_async again :) Rather consider creating an NSOperationQueue and adding these NSOperations to queue :)

QA for your comments

1.What if I create new NSOperationQueue every time instead of adding NSOperations to single NSOperationQueue?

Creating a seperate queue for each NSOperation is never a great idea :)

NSOperationQueue was suggested only with the intention of reducing the complication you will have to bear with multiple threads manually :)

When you submit an NSOperation to NSOperationQueue you can specify how many concurrent operations can be performed by NSOperationQueue.

Notice that it is just an upper value :) If you specify maximum concurrent operation allowed to 10 it means when iOS has resources like memory and CPU cycles it may carry out 10 operations.

You being a developer may not be always in a great position to decide what is the optimal number of threads that system can afford :) but OS can always do it efficiently. So it is always advisable to transfer these burden on OS as much as possible :)

But if you want to have a separate thread for each API calls rather then creating a separate queue you can consider executing the NSOpertaions individually by calling [NSOperation start] Creating an NSOperationQueue for each NSOperation is overhead.

I believe if you have any experience with JAVA you must have came across ExecutorPool concept. NSOperationQueue does exactly what ExecutorPool does for JAVA :)

2.Should I use [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] .. instead of [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init]

I believe you are aware that all you UI operations are performed in main thread and main thread makes use of Main Queue to dispatch the events. Performing the lengthy operations on Main Queue and keeping it busy will lead to a very bad user experience.

Calling 100 API's on Main queue may lead to user uninstalling your app and giving the worst possible rating :)

I guess you now know the answer for your question now :) to be specific use [[NSOperationQueue alloc] init] for your situation.

Sandeep Bhandari
  • 19,999
  • 5
  • 45
  • 78
  • Thanks Sandeep! I think using GCD with NSOperationsQueue will make it more complicated and cumbersome! – Chaitanya Khurana May 17 '16 at 13:23
  • How many queues can be created in iOS? I guess there is no limit for that, right? What if I create new NSOperationQueue every time instead of adding NSOperations to single NSOperationQueue? – Chaitanya Khurana May 17 '16 at 14:05
  • What would be the point of creating a new queue for each request? – Avi May 17 '16 at 14:06
  • @avi Should I use [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] .. instead of [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] ... – Chaitanya Khurana May 17 '16 at 14:39
  • @chaitanya-khurana : I have updated my answer with answer to all your questions have a look :) – Sandeep Bhandari May 17 '16 at 17:02
0

First you should read this: GCD Practicum.

Second you shouldn't roll your own solution here. Instead use AFNetworking, and just make the requests as needed. It has its own operation queue already setup so you don't need to deal with that. Then set the maximum number of concurrent requests to some value that you tune by hand. Start with four.

Community
  • 1
  • 1
i_am_jorf
  • 53,608
  • 15
  • 131
  • 222