objective c - dispatch_sync vs. dispatch_async on main queue -


bear me, going take explaining. have function looks 1 below.

context: "aproject" core data entity named lpproject array named 'memberfiles' contains instances of core data entity called lpfile. each lpfile represents file on disk , want open each of files , parse text, looking @import statements point other files. if find @import statements, want locate file point , 'link' file 1 adding relationship core data entity represents first file. since of can take time on large files, we'll off main thread using gcd.

- (void) establishimportlinksforfilesinproject:(lpproject *)aproject {     dispatch_queue_t taskq = dispatch_get_global_queue(dispatch_queue_priority_default, 0);      (lpfile *filetocheck in aproject.memberfiles) {          if (//some condition met) {             dispatch_async(taskq, ^{                 // here, scanning @import statements.                  // when find valid one, put whole path imported file array called 'verifiedimports'.                   // go main thread , update model (core data not thread-safe.)                 dispatch_sync(dispatch_get_main_queue(), ^{                      nslog(@"got main thread.");                      (nsstring *import in verifiedimports) {                               // add relationship core data lpfile entity.                     }                 });//end block             });//end block         }     } } 

now, here's things weird:

this code works, i'm seeing odd problem. if run on lpproject has few files (about 20), runs perfectly. however, if run on lpproject has more files (say, 60-70), not run correctly. never main thread, nslog(@"got main thread"); never appears , app hangs. but, (and things weird) --- if run code on small project first , run on large project, works perfectly. it's when run code on large project first trouble shows up.

and here's kicker, if change second dispatch line this:

dispatch_async(dispatch_get_main_queue(), ^{ 

(that is, use async instead of sync dispatch block main queue), works time. perfectly. regardless of number of files in project!

i'm @ loss explain behavior. or tips on test next appreciated.

this common issue related disk i/o , gcd. basically, gcd spawning 1 thread each file, , @ point you've got many threads system service in reasonable amount of time.

every time call dispatch_async() , in block attempt to i/o (for example, looks you're reading files here), it's thread in block of code executing block (get paused os) while waits data read filesystem. way gcd works such when sees 1 of worker threads blocked on i/o , you're still asking more work concurrently, it'll spawn new worker thread. if try open 50 files on concurrent queue, it's you'll end causing gcd spawn ~50 threads.

this many threads system meaningfully service, , end starving main thread cpu.

the way fix use serial queue instead of concurrent queue file-based operations. it's easy do. you'll want create serial queue , store ivar in object don't end creating multiple serial queues. remove call:

dispatch_queue_t taskq = dispatch_get_global_queue(dispatch_queue_priority_default, 0);

add in init method:

taskq = dispatch_queue_create("com.yourcompany.yourmeaningfullabel", dispatch_queue_serial);

add in dealloc method:

dispatch_release(taskq);

and add ivar in class declaration:

dispatch_queue_t taskq;


Comments

Popular posts from this blog

c# - SharpSVN - How to get the previous revision? -

c++ - Is it possible to compile a VST on linux? -

url - Querystring manipulation of email Address in PHP -