I have a method that updates two sections in a table that takes awhile. I want to do something like:
dispatch_queue_t lowQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_async(lowQueue, ^{
NSArray *tempArray = // do long running task to get the data
dispatch_async(mainQueue, ^{
// update the main thread
[self.activityIndicatorView stopAnimating];
[self.reportsTableView reloadData];
});
});
dispatch_async(lowQueue, ^{
NSArray *tempArray2 = // same thing, do another long task
// similarly, update the main thread
If I use the same lowQueue in the same method, is that ok? Thanks.
Yes, you can use lowQueue in the same method. When you grab the DISPATCH_QUEUE_PRIORITY_LOW global queue and store a reference to it in lowQueue, you can continue to enqueue additional blocks on it with multiple dispatch_async GCD calls. Every time you call dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), you'll get back a reference to the exact same dispatch queue.
Since all the global dispatch queues are concurrent queues, each block from both of your two tasks will be dequeued and executed simultaneously, provided that GCD determines this is most efficient for the system at runtime (given system load, CPU cores available, number of other threads currently executing, etc).
Related
I've got this method
-(void)addObjectToProcess(NSObject*)object;
and i want this method to add the object to process queue which can process up to 4 objects in parallel.
i've created my own dispatch_queue and semhphore
_concurrentQueue = dispatch_queue_create([queue_id UTF8String],DISPATCH_QUEUE_CONCURRENT);
_processSema = dispatch_semaphore_create(4);
and the implementation of the method is:
-(void)addObjectToProcess(NSObject*)object {
dispatch_semaphore_wait(self.processSema, DISPATCH_TIME_FOREVER);
__weak MyViewController* weakSelf = self;
dispatch_async(self.concurrentQueue, ^{
// PROCESS...........
// ..................
dispatch_semaphore_signal(self.processSema);
dispatch_async(dispatch_get_main_queue(), ^{
// call delegate from UI thread
});
});
}
it seems the caller sometimes gets blocked cause of the semaphore barrier.
is there any other/easier option to implement what i'm trying to make here ?
Thanks
The problem is that you're calling dispatch_semaphore_wait on whatever thread you called addObjectToProcess on (presumably the main thread). Thus, if you already have four tasks running, when you schedule this fifth process, it will wait on the main thread.
You don't, though, just want to move the waiting for the semaphore into the block dispatched to self.concurrentQueue, because while that will successfully constrain the "PROCESS" tasks to four at a time, you will consume another worker thread for each one of these backlogged dispatched tasks, and there are a finite number of those worker threads. And when you exhaust those, you could adversely affect other processes.
One way to address this would be to create a serial scheduling queue in addition to your concurrent processing queue, and then dispatch this whole scheduling task asynchronously to this scheduling queue. Thus you enjoy the maximum concurrency on the process queue, while neither blocking the main thread nor using up worker threads for backlogged tasks. For example:
#property (nonatomic, strong) dispatch_queue_t schedulingQueue;
And
self.schedulingQueue = dispatch_queue_create("com.domain.scheduler", 0);
And
- (void)addObjectToProcess(NSObject*)object {
dispatch_async(self.schedulingQueue, ^{
dispatch_semaphore_wait(self.processSema, DISPATCH_TIME_FOREVER);
typeof(self) __weak weakSelf = self;
dispatch_async(self.concurrentQueue, ^{
// PROCESS...........
// ..................
typeof(self) __strong strongSelf = weakSelf;
if (strongSelf) {
dispatch_semaphore_signal(strongSelf.processSema);
dispatch_async(dispatch_get_main_queue(), ^{
// call delegate from UI thread
});
}
});
});
}
Another good approach (especially if the "PROCESS" is synchronous) is to use NSOperationQueue that has a maxConcurrentOperationCount, which controls the degree of concurrency for you. For example:
#property (nonatomic, strong) NSOperationQueue *processQueue;
And initialize it:
self.processQueue = [[NSOperationQueue alloc] init];
self.processQueue.maxConcurrentOperationCount = 4;
And then:
- (void)addObjectToProcess(NSObject*)object {
[self.processQueue addOperationWithBlock:^{
// PROCESS...........
// ..................
dispatch_async(dispatch_get_main_queue(), ^{
// call delegate from UI thread
});
}];
}
The only trick is if the "PROCESS", itself, is asynchronous. If you do that, then you can't just use addOperationWithBlock, but rather have to write your own custom, asynchronous NSOperation subclass, and then use addOperation to the NSOperationQueue. It's not hard to write asynchronous NSOperation subclass, but there are a few little details associated with that. See Configuring Operations for Concurrent Execution in the Concurrency Programming Guide.
I have a question about threading. I have a view which displays two images (Banner of the opponents). I have read about threads groups which can run together.
The way I have it now is:
- (void) setBanners{
[getBanner:#"TeamA"];
[getBanner:#"TeamB"];
}
- getBanner:(NSString *team){
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^(void){
..Goto server and get logo
}
}
So my question is, does this happen the same way as grouping threads or does team two method get called when one is finished ? With grouping it would look like this:
- setBanner{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{
get logo team a
});
dispatch_group_async(group, queue, ^{
get logo team a
});
}
for that they are almost equal.. there is no difference except that the dispatch_group reuses threads implicitly since GCD has a thread pool
-- oh and obviously GCD uses blocks
I have a scenario in my app, where I want to do some time consuming task which consists of some data processing as well as UI update, in a method. My method looks like this,
- (void)doCalculationsAndUpdateUIs {
// DATA PROCESSING 1
// UI UPDATE 1
// DATA PROCESSING 2
// UI UPDATE 2
// DATA PROCESSING 3
// UI UPDATE 3
}
As it is time consuming I wanted to do the data processing on the background thread, using,
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL), ^{
But as both data processing and UI updates are in the same method, I wanted to move only the UI updates in main thread using,
dispatch_async(dispatch_get_main_queue(), ^{
Finally my method looks like this,
- (void)doCalculationsAndUpdateUIs {
// DATA PROCESSING 1
dispatch_async(dispatch_get_main_queue(), ^{
// UI UPDATE 1
});
/* I expect the control to come here after UI UPDATE 1 */
// DATA PROCESSING 2
dispatch_async(dispatch_get_main_queue(), ^{
// UI UPDATE 2
});
/* I expect the control to come here after UI UPDATE 2 */
// DATA PROCESSING 3
dispatch_async(dispatch_get_main_queue(), ^{
// UI UPDATE 3
});
}
Does this really work? Is this really a good practice? What is the best way to achieve this?
P.S. All these three operations are interrelated to each other.
EDIT: Sorry guys. I have missed a line in the above code. My actual code looks like this.
- (void)doCalculationsAndUpdateUIs {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// DATA PROCESSING 1
dispatch_async(dispatch_get_main_queue(), ^{
// UI UPDATE 1
});
/* I expect the control to come here after UI UPDATE 1 */
// DATA PROCESSING 2
dispatch_async(dispatch_get_main_queue(), ^{
// UI UPDATE 2
});
/* I expect the control to come here after UI UPDATE 2 */
// DATA PROCESSING 3
dispatch_async(dispatch_get_main_queue(), ^{
// UI UPDATE 3
});
});
}
Once again, I really apologize for the confusion.
No it doesn't wait and the way you are doing it in that sample is not good practice.
dispatch_async is always asynchronous. It's just that you are enqueueing all the UI blocks to the same queue so the different blocks will run in sequence but parallel with your data processing code.
If you want the update to wait you can use dispatch_sync instead.
// This will wait to finish
dispatch_sync(dispatch_get_main_queue(), ^{
// Update the UI on the main thread.
});
Another approach would be to nest enqueueing the block. I wouldn't recommend it for multiple levels though.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Background work
dispatch_async(dispatch_get_main_queue(), ^{
// Update UI
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Background work
dispatch_async(dispatch_get_main_queue(), ^{
// Update UI
});
});
});
});
If you need the UI updated to wait then you should use the synchronous versions. It's quite okay to have a background thread wait for the main thread. UI updates should be very quick.
You have to put your main queue dispatching in the block that runs the computation. For example (here I create a dispatch queue and don't use a global one):
dispatch_queue_t queue = dispatch_queue_create("com.example.MyQueue", NULL);
dispatch_async(queue, ^{
// Do some computation here.
// Update UI after computation.
dispatch_async(dispatch_get_main_queue(), ^{
// Update the UI on the main thread.
});
});
Of course, if you create a queue don't forget to dispatch_release if you're targeting an iOS version before 6.0.
Your proposed doCalculationsAndUpdateUIs does data processing and dispatches UI updates to the main queue. I presume that you have dispatched doCalculationsAndUpdateUIs to a background queue when you first called it.
While technically fine, that's a little fragile, contingent upon your remembering to dispatch it to the background every time you call it: I would, instead, suggest that you do your dispatch to the background and dispatch back to the main queue from within the same method, as it makes the logic unambiguous and more robust, etc.
Thus it might look like:
- (void)doCalculationsAndUpdateUIs {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL), ^{
// DATA PROCESSING 1
dispatch_async(dispatch_get_main_queue(), ^{
// UI UPDATION 1
});
/* I expect the control to come here after UI UPDATION 1 */
// DATA PROCESSING 2
dispatch_async(dispatch_get_main_queue(), ^{
// UI UPDATION 2
});
/* I expect the control to come here after UI UPDATION 2 */
// DATA PROCESSING 3
dispatch_async(dispatch_get_main_queue(), ^{
// UI UPDATION 3
});
});
}
In terms of whether you dispatch your UI updates asynchronously with dispatch_async (where the background process will not wait for the UI update) or synchronously with dispatch_sync (where it will wait for the UI update), the question is why would you want to do it synchronously: Do you really want to slow down the background process as it waits for the UI update, or would you like the background process to carry on while the UI update takes place.
Generally you would dispatch the UI update asynchronously with dispatch_async as you've used in your original question. Yes, there certainly are special circumstances where you need to dispatch code synchronously (e.g. you're synchronizing the updates to some class property by performing all updates to it on the main queue), but more often than not, you just dispatch the UI update asynchronously and carry on. Dispatching code synchronously can cause problems (e.g. deadlocks) if done sloppily, so my general counsel is that you should probably only dispatch UI updates synchronously if there is some compelling need to do so, otherwise you should design your solution so you can dispatch them asynchronously.
In answer to your question as to whether this is the "best way to achieve this", it's hard for us to say without knowing more about the business problem being solved. For example, if you might be calling this doCalculationsAndUpdateUIs multiple times, I might be inclined to use my own serial queue rather than a concurrent global queue, in order to ensure that these don't step over each other. Or if you might need the ability to cancel this doCalculationsAndUpdateUIs when the user dismisses the scene or calls the method again, then I might be inclined to use a operation queue which offers cancelation capabilities. It depends entirely upon what you're trying to achieve.
But, in general, the pattern of asynchronously dispatching a complicated task to a background queue and then asynchronously dispatching the UI update back to the main queue is very common.
No, it won't wait.
You could use performSelectorOnMainThread:withObject:waitUntilDone:.
If you want to run a single independent queued operation and you’re not concerned with other concurrent operations, you can use the global concurrent queue:
dispatch_queue_t globalConcurrentQueue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
This will return a concurrent queue with the given priority as outlined in the documentation:
DISPATCH_QUEUE_PRIORITY_HIGH Items dispatched to the queue will run at high priority, i.e. the queue will be scheduled for execution before any default priority or low priority queue.
DISPATCH_QUEUE_PRIORITY_DEFAULT Items dispatched to the queue will run at the default priority, i.e. the queue will be scheduled for execution after all high priority queues have been scheduled, but before any low priority queues have been scheduled.
DISPATCH_QUEUE_PRIORITY_LOW Items dispatched to the queue will run at low priority, i.e. the queue will be scheduled for execution after all default priority and high priority queues have been scheduled.
DISPATCH_QUEUE_PRIORITY_BACKGROUND Items dispatched to the queue will run at background priority, i.e. the queue will be scheduled for execution after all higher priority queues have been scheduled and the system will run items on this queue on a thread with background status as per setpriority(2) (i.e. disk I/O is throttled and the thread’s scheduling priority is set to lowest value).
dispatch_queue_t queue = dispatch_queue_create("com.example.MyQueue", NULL);
dispatch_async(queue, ^{
// Do some computation here.
// Update UI after computation.
dispatch_async(dispatch_get_main_queue(), ^{
// Update the UI on the main thread.
});
});
The good practice is: Dispatch Groups
dispatch_group_t imageGroup = dispatch_group_create();
dispatch_group_enter(imageGroup);
[uploadImage executeWithCompletion:^(NSURL *result, NSError* error){
// Image successfully uploaded to S3
dispatch_group_leave(imageGroup);
}];
dispatch_group_enter(imageGroup);
[setImage executeWithCompletion:^(NSURL *result, NSError* error){
// Image url updated
dispatch_group_leave(imageGroup);
}];
dispatch_group_notify(imageGroup,dispatch_get_main_queue(),^{
// We get here when both tasks are completed
});
OK, there are two ways of doing that:
// GLOBAL_CONCURRENT_QUEUE
- (void)doCalculationsAndUpdateUIsWith_GlobalQUEUE
{
dispatch_queue_t globalConcurrentQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(globalConcurrentQ, ^{
// DATA PROCESSING 1
sleep(1);
NSLog(#"Hello world chekpoint 1");
dispatch_sync(dispatch_get_main_queue(), ^{
// UI UPDATION 1
sleep(1);
NSLog(#"Hello world chekpoint 2");
});
/* the control to come here after UI UPDATION 1 */
sleep(1);
NSLog(#"Hello world chekpoint 3");
// DATA PROCESSING 2
dispatch_sync(dispatch_get_main_queue(), ^{
// UI UPDATION 2
sleep(1);
NSLog(#"Hello world chekpoint 4");
});
/* the control to come here after UI UPDATION 2 */
sleep(1);
NSLog(#"Hello world chekpoint 5");
// DATA PROCESSING 3
dispatch_sync(dispatch_get_main_queue(), ^{
// UI UPDATION 3
sleep(1);
NSLog(#"Hello world chekpoint 6");
});
});
}
// SERIAL QUEUE
- (void)doCalculationsAndUpdateUIsWith_GlobalQUEUE
{
dispatch_queue_t serialQ = dispatch_queue_create("com.example.MyQueue", NULL);
dispatch_async(serialQ, ^{
// DATA PROCESSING 1
sleep(1);
NSLog(#"Hello world chekpoint 1");
dispatch_sync(dispatch_get_main_queue(), ^{
// UI UPDATION 1
sleep(1);
NSLog(#"Hello world chekpoint 2");
});
sleep(1);
NSLog(#"Hello world chekpoint 3");
// DATA PROCESSING 2
dispatch_sync(dispatch_get_main_queue(), ^{
// UI UPDATION 2
sleep(1);
NSLog(#"Hello world chekpoint 4");
});
});
}
Here is what I need to do.
I hope dispatch_sync would be the best way to do it using GCD
I have a certain piece of critical section code that is placed in the applicationDidBecomeActive callback in Appdelegate..
I am wrapping up that method inside a dispatch_sync call so that it gets called only once no matter how many times applicationDidBecomeActive is called
- (void)applicationDidBecomeActive:(UIApplication *)application{
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(#"Thread created");
//crtical code
[self runCriticalSection];
});}
Is this the right way for doing it using dispatch_sync?
dispatch_sync() does not return until the block has finished, which means that
applicationDidBecomeActive does not return until runCriticalSection has finished
execution.
This is probably not what you want, therefore you have to use dispatch_async() (as already
stated in the other answer).
But you don't want another runCriticalSection to start
if the previous one is still running. This can be achieved with a "counting semaphore"
(which are also a feature of GCD):
static dispatch_semaphore_t sema; // The semaphore
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// Initialize with count=1 (this is executed only once):
sema = dispatch_semaphore_create(1);
});
// Try to decrement the semaphore. This succeeds if the count is still 1
// (meaning that runCriticalSection is not executing), and fails if the
// current count is 0 (meaning that runCriticalSection is executing):
if (dispatch_semaphore_wait(sema, DISPATCH_TIME_NOW) == 0) {
// Success, semaphore count is now 0.
// Start asynchronous operation.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//critical code
[self runCriticalSection];
// Increment the semaphore count (from 0 to 1), so that the next call
// to applicationDidBecomeActive will start a new operation:
dispatch_semaphore_signal(sema);
});
}
The runCriticalSection method will be called multiple times, just not concurrently, so I don't know if this is what you want to achieve.
dispatch_sync just add the specified block to a serial queue (the default priority global queue), so if applicationDidBecomeActive gets fired two times in a row, the queue will contain two blocks that will run runCriticalSection. As the first one starts and finishes its execution, the second one will start, so there will not be any execution of the two blocks at the same time.
Is this the expected behavior? If so, dispatch_sync is the way to go.
As an add-on: if runCriticalSection performs an heavy operation, consider that dispatch_sync will block the thread that runs the applicationDidBecomeActive method (the main one if you don't call the method by hand from another thread) until that operation is finished.
If you want to avoid this, you should do something like:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self runCriticalSectionOnComplete:^{
// If you want to perform something on completion, place it here. This is called asynchronously, without blocking the main thread.
}];
});
dispatch_async will return as soon as the block is added to the queue, while dispatch_sync waits for the code inside the block to be completed.
I need to perform an asynchronous function execution because it is blocking the main thread and hence the UI is not available.
After looking at the questions in stackoverflow, I know there are three ways to do asynchronous function.
An example:
[NSThread detachNewThreadSelector:#selector(showSpinner:) toTarget:self withObject:self.view];
// or
[self performSelectorInBackground:#selector(showSpinner:) withObject:self.view];
// or
NSInvocationOperation *invOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(showSpinner:) object:self.view];
NSOperationQueue *opQueue = [[NSOperationQueue alloc] init];
[opQueue addOperation:invOperation];
// or
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_async(dispatch_get_main_queue(), ^{
[self showSpinner:self.view];
});
});
My question is how does performSelectorInBackground and detachNewThreadSelector return back to main thread? how do you know that they are done?
A couple of thoughts:
You might want to check Migrating Away From Threads in the Concurrency Programming Guide, which makes a compelling argument for dispatch queues and operation queues, which are discussed earlier in that same guide.
Also, as you delve into various asynchronous operations, remember, do time consuming stuff in background queues/threads, but always dispatch UI stuff back to the main queue. I only mention that because your task, showSpinner sounds a lot like a UI task, which you would never want to do in a background queue/thread. If it has some "expensive" non-UI related tasks, then fine, do that in the background, but make sure the UI stuff gets dispatched back to the main queue.
There are, as an aside, other renditions of the operations queues, e.g., block operations:
NSOperationQueue *opQueue = [[NSOperationQueue alloc] init];
[opQueue addOperationWithBlock:^{
// do some slow stuff in the background here
// ok, now do UI stuff in the main queue
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self showSpinner:self.view];
}];
}];
This is roughly equivalent to the GCD (dispatch queue) rendition:
dispatch_queue_t dispatchQueue = dispatch_queue_create("com.ramshad.app", 0);
dispatch_async(dispatchQueue, ^{
// do some slow stuff in the background here
// ok, now do UI stuff in the main queue
dispatch_async(dispatch_get_main_queue(), ^{
[self showSpinner:self.view];
});
});
There are tons of subtle pros and cons between the operation queues and dispatch queues (which we should not get into here because it's been discussed hundreds of times elsewhere on Stack Overflow), but both let you do surprisingly rich asynchronous operations with less complexity than traditional thread programming.
If you decide to stick with threads versus operation and/or dispatch queues (which I wouldn't necessarily recommend), you might want to check out the Threading Programming Guide.
To identify performSelectorInBackground & detachNewThreadSelector end of execution,call a method at the end of the thread method on main thread.
Additionaly NSThread provides an propery as isFinished which returns a Boolean value that indicates whether the receiver has finished execution.
Example:
[self performSelectorOnMainThread:#selector(threadMethod)
withObject:nil
waitUntilDone:NO];
or
[NSThread detachNewThreadSelector:#selector(threadMethod)
toTarget:self
withObject:nil];
-(void)threadMethod{
//here your implementation code
//here call the end notification method.
[self performSelectorOnMainThread:#selector(ThreadExecutionDone)
withObject:nil
waitUntilDone:YES];
}
-(void)ThreadExecutionDone{
//end of the performSelectorInBackground or detachNewThreadSelector.
}