Grand Central Dispatch and concurrent tasks - ios

I need to perform three tasks that are independent one from each other, so I'd like to execute them concurrently. But I need them all to have finished to notify another object. AFAIK, *dispatch_apply* creates concurrent threads, but it iterates a collection or an array of objects and performs the same task a number of loops, and I want to perform a different task for each thread. Is it possible to do what I want by using GCD? If not, what should be the best way?
Thanks!

Use a dispatch_group. The Concurrency Programming Guide gives one example, and there is more API that might also help you.
Create a dispatch group using dispatch_group_create.
Put each "task" in the group by enqueuing it using dispatch_group_async.
(Or, manually tell GCD when each task starts and stops, using dispatch_group_enter and dispatch_group_leave.)
To run a block when all tasks in the group have completed, enqueue it using dispatch_group_notify.
(Or, in the unlikely case that the design of your app allows you to wait synchronously, use dispatch_group_wait instead.)
When you're done with the group, dispatch_release it.

Dispatch Groups are what you need. Look at the GCD functions. What you will do is create the group and a concurrent queue (or use thee standard ones). Associate the three operations (blocks) with the dispatch_group, then create a forth block, and have that block do a dispatch_group_wait (typing names by memory), then when that returns, it can post a 'success' message to some other object. Put the block with the wait into any concurrent queue.
I do exactly this in my app.

I know you asked about GCD, but NSOperationQueue is another possibility. For example:
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 3;
// create my completion operation (which will be added to the queue later, once
// the dependencies with all of the other operations has been established)
NSBlockOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(#"All done");
}];
// let's add our three operations
NSBlockOperation *operation;
operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(#"starting task 1");
sleep(5);
NSLog(#"stopping task 1");
}];
[completionOperation addDependency:operation];
[queue addOperation:operation];
operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(#"starting task 2");
sleep(4);
NSLog(#"stopping task 2");
}];
[completionOperation addDependency:operation];
[queue addOperation:operation];
operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(#"starting task 3");
sleep(6);
NSLog(#"stopping task 3");
}];
[completionOperation addDependency:operation];
[queue addOperation:operation];
// now let's add the completion operation (which has been configured as dependent
// upon the other operations
[queue addOperation:completionOperation];
There are tons of different ways of tackling this problem, but NSOperationQueue is another option. The Concurrency Programming Guide discusses all of the options.

Related

dispatch_group_t or dispatch_semaphore_t to wait for multiple async requests to complete

I need to wait for several requests to complete before I can move on to the next task. dispatch_group_t & dispatch_semaphore_t like quite similar here. So I was wondering which one is better or there is no much difference here.
dispatch_group_t serviceGroup = dispatch_group_create();
dispatch_group_enter(serviceGroup);
// in completion block
dispatch_group_leave(serviceGroup);
//wait for all requests to complete
dispatch_group_notify(serviceGroup,dispatch_get_main_queue(),^{
// Won't get here until everything has finished
});
/* Or I can use dispatch_semaphore_t */
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
// in completion block
dispatch_semaphore_signal(sem);
// before start request
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
// Reaching here means all requests has completed
...
In this particular situation, the key difference is that the semaphore approach keeps the thread that calls dispatch_semaphore_wait alive, but blocked for the entire time, whereas dispatch_group_notify returns right away, only executing the block later, leaving the calling thread free to do other things. I would say that dispatch_group_notify is the better way to go in this case.

Does AFHTTPRequestOperationManager run requests on the operationQueue?

If I have a manager created and instance-varred and I do:
AFHTTPRequestOperation *operation = [self.manager HTTPRequestOperationWithRequest:request success:mySuccessBlock failure:myFailureBlock];
[operation start];
will this run on the manager's operationQueue? I can't seem to find anything guaranteeing it will verse using one of the GET, POST, PUT methods instead which I assume will add the operation to the queue.
I see mattt's answer here, but I want to be sure one way or the other.
How send request with AFNetworking 2 in strict sequential order?
What I'm trying to do is queue up requests and have them run synchronously by setting
[self.manager.operationQueue setMaxConcurrentOperationCount:1];
If you want to run an operation on a queue, you have to explicitly add the operation to the queue:
AFHTTPRequestOperation *operation = [self.manager HTTPRequestOperationWithRequest:request success:mySuccessBlock failure:myFailureBlock];
[queue addOperation:operation];
This presumes that you would create a queue:
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.name = #"com.domain.app.networkQueue";
queue.maxConcurrentOperationCount = 1;
If you just start the operations without adding them to a queue (e.g. [operation start]), they'll just run, without honoring any particular queue parameters.
Note, you could also have added your operation to the operation manager's queue (which you can set the maxConcurrentOperationCount, as you alluded to in your question):
[self.manager.operationQueue addOperation:operation];
That saves you from having to create your own queue. But it then presumes that all of your other AFNetworking requests for this manager would also run serially, too. Personally, I'd leave manager.operationQueue alone, and create a dedicated queue for my logic that required serial operations.
One final note: Using serial network operations imposes a significant performance penalty over concurrent requests. I'll assume from your question that you absolutely need to do it serially, but in general I now design my apps to use concurrent requests wherever possible, as it's a much better UX. If I need a particular operation to be serial (e.g. the login), then I do that with operation dependencies or completion blocks, but the rest of the app is running concurrent network requests wherever possible.

dispatch_queue and Thread and task order

guys,little confused abt dispatch queue and thread,
there could be several queues and they dispatch tasks to different thread,
if the queue is serial, tasks executed in a line and may be in different, its not a problem.
but if we have 2 serial queues,can we manage order of them ?
if we put some Database operations in these 2 queues, the data may be wrong?
If these two queues serve different functional purposes that merit having separate queues, that's fine, but you'd probably just set up a third queue for database interaction, to which those two would dispatch their database interactions. Let this third queue, a dedicate low-level database queue, coordinate all interaction with the database.
If these two queues are just two random database interaction queues, then one might argue for refactoring the code to consolidate them into one.
Yes, you can manage the order. But not with dispatch_queue. You have to use NSOperationQueue:
NSOperationQueue * queue = [[NSOperationQueue alloc] init];
NSBlockOperation * operation1 = [NSBlockOperation blockOperationWithBlock:^{
// do something
}];
[queue addOperation:operation1];
NSBlockOperation * operation2 = [NSBlockOperation blockOperationWithBlock:^{
// do something
}];
[operation2 addDependency:operation1];
[queue addOperation:operation2];
In this code operation2 will start only when operation1 did complete.

NSOperation and NSOperationQueue working thread vs main thread

I have to carry out a series of download and database write operations in my app. I am using the NSOperation and NSOperationQueue for the same.
This is application scenario:
Fetch all postcodes from a place.
For each postcode fetch all houses.
For each house fetch inhabitant details
As said, I have defined an NSOperation for each task. In first case (Task1), I am sending a request to server to fetch all postcodes. The delegate within the NSOperation will receive the data. This data is then written to database. The database operation is defined in a different class. From NSOperation class I am making a call to the write function defined in database class.
My question is whether the database write operation occur in main thread or in a background thread? As I was calling it within a NSOperation I was expecting it to run in a different thread (Not MainThread) as the NSOperation. Can someone please explain this scenario while dealing with NSOperation and NSOperationQueue.
My question is whether the database write operation occur in main
thread or in a background thread?
If you create an NSOperationQueue from scratch as in:
NSOperationQueue *myQueue = [[NSOperationQueue alloc] init];
It will be in a background thread:
Operation queues usually provide the threads used to run their
operations. In OS X v10.6 and later, operation queues use the
libdispatch library (also known as Grand Central Dispatch) to initiate
the execution of their operations. As a result, operations are always
executed on a separate thread, regardless of whether they are
designated as concurrent or non-concurrent operations
Unless you are using the mainQueue:
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
You can also see code like this:
NSOperationQueue *myQueue = [[NSOperationQueue alloc] init];
[myQueue addOperationWithBlock:^{
// Background work
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
// Main thread work (UI usually)
}];
}];
And the GCD version:
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void)
{
// Background work
dispatch_async(dispatch_get_main_queue(), ^(void)
{
// Main thread work (UI usually)
});
});
NSOperationQueue gives finer control with what you want to do. You can create dependencies between the two operations (download and save to database). To pass the data between one block and the other, you can assume for example, that a NSData will be coming from the server so:
__block NSData *dataFromServer = nil;
NSBlockOperation *downloadOperation = [[NSBlockOperation alloc] init];
__weak NSBlockOperation *weakDownloadOperation = downloadOperation;
[weakDownloadOperation addExecutionBlock:^{
// Download your stuff
// Finally put it on the right place:
dataFromServer = ....
}];
NSBlockOperation *saveToDataBaseOperation = [[NSBlockOperation alloc] init];
__weak NSBlockOperation *weakSaveToDataBaseOperation = saveToDataBaseOperation;
[weakSaveToDataBaseOperation addExecutionBlock:^{
// Work with your NSData instance
// Save your stuff
}];
[saveToDataBaseOperation addDependency:downloadOperation];
[myQueue addOperation:saveToDataBaseOperation];
[myQueue addOperation:downloadOperation];
Edit: Why I am using __weak reference for the Operations, can be found here. But in a nutshell is to avoid retain cycles.
If you want to perform the database writing operation in the background thread you need to create a NSManagedObjectContext for that thread.
You can create the background NSManagedObjectContext in the start method of your relevant NSOperation subclass.
Check the Apple docs for Concurrency with Core Data.
You can also create an NSManagedObjectContext that executes requests in its own background thread by creating it with NSPrivateQueueConcurrencyType and performing the requests inside its performBlock: method.
From NSOperationQueue
In iOS 4 and later, operation queues use Grand Central Dispatch to execute operations. Prior to iOS 4, they create separate threads for non-concurrent operations and launch concurrent operations from the current thread.
So,
[NSOperationQueue mainQueue] // added operations execute on main thread
[NSOperationQueue new] // post-iOS4, guaranteed to be not the main thread
In your case, you might want to create your own "database thread" by subclassing NSThread and send messages to it with performSelector:onThread:.
The execution thread of NSOperation depends on the NSOperationQueue where you added the operation. Look out this statement in your code -
[[NSOperationQueue mainQueue] addOperation:yourOperation]; // or any other similar add method of NSOperationQueue class
All this assumes you have not done any further threading in main method of NSOperation which is the actual monster where the work instructions you have (expected to be) written.
However, in case of concurrent operations, the scenario is different. The queue may spawn a thread for each concurrent operation. Although it's not guarrantteed and it depends on system resources vs operation resource demands at that point in the system. You can control concurrency of operation queue by it's maxConcurrentOperationCount property.
EDIT -
I found your question interesting and did some analysis/logging myself. I have NSOperationQueue created on main thread like this -
self.queueSendMessageOperation = [[[NSOperationQueue alloc] init] autorelease];
NSLog(#"Operation queue creation. current thread = %# \n main thread = %#", [NSThread currentThread], [NSThread mainThread]);
self.queueSendMessageOperation.maxConcurrentOperationCount = 1; // restrict concurrency
And then, I went on to create an NSOperation and added it using addOperation. In the main method of this operation when i checked for current thread,
NSLog(#"Operation obj = %#\n current thread = %# \n main thread = %#", self, [NSThread currentThread], [NSThread mainThread]);
it was not as main thread. And, found that current thread object is not main thread object.
So, custom creation of queue on main thread (with no concurrency among its operation) doesn't necessarily mean the operations will execute serially on main thread itself.
The summary from the docs is operations are always executed on a separate thread (post iOS 4 implies GCD underlying operation queues).
It's trivial to check that it is indeed running on a non-main thread:
NSLog(#"main thread? %#", [NSThread isMainThread] ? #"YES" : #"NO");
When running in a thread it's trivial to use GCD/libdispatch to run something on the main thread, whether core data, user interface or other code required to run on the main thread:
dispatch_async(dispatch_get_main_queue(), ^{
// this is now running on the main thread
});
If you're doing any non-trivial threading, you should use FMDatabaseQueue.

Simple GCD Serial Queue example like FIFO using blocks

I read Apple documentation on how to Use serial queues to ensure that tasks to execute in a predictable order but now i am confused too much.
Some how i am able to work serially but still i am not clear so i need simple serial example for my methods to execute serially.
I divided my functionality in to 4 parts and now want them to execute Serially
[self ReadAllImagesFromPhotosLibrary];
[self WriteFewImagestoDirectory];
[self GettingBackAllImagesFromFolder];
[self MoveToNextView];
To follow-up and improve iCoder's answer, you could and should do the following.
dispatch_queue_t serialQueue = dispatch_queue_create("com.unique.name.queue", DISPATCH_QUEUE_SERIAL);
dispatch_async(serialQueue, ^{
[self ReadAllImagesFromPhotosLibrary];
});
dispatch_async(serialQueue, ^{
[self WriteFewImagestoDirectory];
});
dispatch_async(serialQueue, ^{
[self GettingBackAllImagesFromFolder];
});
dispatch_async(serialQueue, ^{
[self MoveToNextView];
});
Despite the above calls being async, they will be queued and run serially as the DISPATCH_QUEUE_SERIAL states. The difference between sync and async is that with sync, your code will pause and wait for the block answer before running the following code, thus potentially freezing your UI if the execution time is long. Whereas with async, the code runs on and the block is returned asynchronously.
However, the tasks you have stored in the DISPATCH_QUEUE_SERIAL will wait and be executed one after the other in the order they were added, thanks to GCD (Grand Central Dispatch).
dispatch_queue_t serialQueue = dispatch_queue_create("com.unique.name.queue", DISPATCH_QUEUE_SERIAL);
dispatch_async(serialQueue, ^{
[self ReadAllImagesFromPhotosLibrary];
dispatch_async(serialQueue, ^{
[self WriteFewImagestoDirectory];
dispatch_async(serialQueue, ^{
[self GettingBackAllImagesFromFolder];
dispatch_async(serialQueue, ^{
[self MoveToNextView];
});
});
});
});
I think the above code should work, but make sure the UI operations are executed in the main thread. Hope it helps.
You can use NSOperationQueue with maxConcurrentOperationCount set to 1 (or even set dependency for each NSOperation, so it won't start before its dependency is finished).
Here is NSOperationQueue Class Reference.
Also take a look at this question.
I am not much aware of existing API for doing the same with blocks, if any.
But the same can be done by defining blocks(representing the operations you want) in a fashion that they point to next block to proceed if any. Also, you can put the whole processing in a separate queue.
snippet for having blocks executing in serial fashion
BLOCK A(NEXT BLOCK reference){
->Do the the required Task
->If(next Block reference)
--->Then call that block
->Else
--->Exit or have a callback on mainthread
}
why not try the GCD, it guarantees the sequence of operation and also has sync and async capabilities
I had some success with a pattern like this in a similar hunt in Swift 3.0 ...
let serialQueue = DispatchQueue.init(label: "com.foo.bar")
serialQueue.sync {self.readAllImagesFromPhotosLibrary()}
serialQueue.sync {self.rriteFewImagestoDirectory()}
serialQueue.sync {self.gettingBackAllImagesFromFolder()}
serialQueue.sync {self.moveToNextView()}

Resources