CFRunLoopPerformBlock vs dispatch_async

I have some work on calculating in the background thread, after which I need to update the conversion of some number, I'm trying to use

dispatch_async(dispatch_get_main_queue(), ^{calayer.transform = newTransform}); 

and

 CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopCommonModes, ^(void) {calayer.transform = newTransform}); 

I just thought they were the same, but I found that when using dispatch_async, callers worked a lot smoothly (maybe?). What is different from these two functions?

+8
multithreading ios grand-central-dispatch
source share
3 answers

The main difference here is that CFRunLoopPerformBlock allows CFRunLoopPerformBlock to specify specific run-cycle modes in which you want to execute the block, whereas dispatch_async(dispatch_get_main_queue(),...) will only be executed in general modes. Perhaps more about the performance issue you see, CFRunLoopPerformBlock does not wake up the main thread. From the documentation for CFRunLoopPerformBlock :

This method blocks only the block and the specified execution cycle does not automatically wake up. Therefore, the execution of the block occurs the next time the run cycle wakes up to process another input source. if you want the work to be done right away, you should explicitly wake up that using the CFRunLoopWakeUp function.

In practice, this usually means that your block will not be executed until the execution cycle wakes up (i.e., a user event occurs, a timer is triggered, the start source starts, the message is mach, etc.) GCD is not , by design, a loop-based API; the relationship between the main queue and the main thread launch cycle is, in fact, an implementation detail. I would expect this implementation to trigger the execution cycle itself, if necessary to serve the main queue.

The lack of information to the contrary, I strongly suspect that this is the source of the difference in performance. I would expect the performance to be the same if you added a call to CFRunLoopWakeUp right after your call to CFRunLoopPerformBlock .

+13
source share

The main GCD queue is the next queue. Thus, it can only run one task at a time. Even if this task performs an internal loop of the cycle, for example, starts a modal dialog, then other tasks sent to the main queue cannot be executed until this is completed.

Tasks dispatched using CFRunLoopPerformBlock() can be executed whenever the start cycle starts in one of the target modes. This includes if the run loop starts from a task that was submitted using CFRunLoopPerformBlock() .

Consider the following examples:

 CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopCommonModes, ^{ printf("outer task milestone 1\n"); CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopCommonModes, ^{ printf("inner task\n"); }); [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]]; printf("outer task milestone 2\n"); }); 

produces a conclusion, for example:

 outer task milestone 1 inner task outer task milestone 2 

So far it is:

 dispatch_async(dispatch_get_main_queue(), ^{ printf("outer task milestone 1\n"); dispatch_async(dispatch_get_main_queue(), ^{ printf("inner task\n"); }); [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]]; printf("outer task milestone 2\n"); }); 

gives:

 outer task milestone 1 outer task milestone 2 inner task 
+3
source share

I sometimes use them together:

 dispatch_async(dispatch_get_main_queue(), ^(void) { CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopDefaultMode, ^{ // stuff }); }); 

I use this to send a block to the main thread, which will be executed without causing "crashes" when scrolling UIScrollview.

I also recently used:

 CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopDefaultMode, ^{ // stuff }); 

instead:

 [self performSelector:@selector(myMethod:) withObject:myObject afterDelay:0] 

to delay code execution until the next pass through runloop. Thus, I do not need to create a special method for the content of the code I want to execute, and I do not need to include all the parameters for execution in one (id) myObject.

+1
source share

All Articles