ios - How to parallelize many (100+) tasks without hitting global GCD limit? -
the problem:
when lazy-loading list of 100+ icons in background, hit gcd thread limit (64 threads), causes app freeze semaphore_wait_trap
on main thread. want restructure threading code prevent happening, while still loading icons asynchronous prevent ui blocking.
context:
my app loads screen svg icons on it. amount differs on average 10-200. icons drawn using local svg image or remote svg image (if has custom icon), post-processed final image result.
because takes time, , aren't vital user, want load , post-process them in background, pop in on time. every icon use following:
dispatch_queue_t concurrentqueue = dispatch_get_global_queue(dispatch_queue_priority_default, 0); dispatch_async(concurrentqueue, ^{ //code executed in background svgkimage *iconimage = [settings geticonimage:location]; dispatch_async(dispatch_get_main_queue(), ^{ //code executed on main thread when background task finished if (iconimage) { [iconimgview setimage:iconimage.uiimage]; } }); });
the geticonimage
method handles initial loading of base svg, reads synchronized [nsinputstream inputstreamwithfileatpath:path]
if local, , [nsurlconnection sendsynchronousrequest:request returningresponse:&response error:&errorwithnsdata]
if should load remotely. happens synchronous.
then there post-processing of recoloring svg, before gets returned , put in uiimageview
on main thread.
question:
is there way structure code allow parallelized background loading prevent deadlock because of many threads?
solution edit:
_iconoperationqueue = [[nsoperationqueue alloc]init]; _iconoperationqueue.maxconcurrentoperationcount = 8; // code executed on background [_iconoperationqueue addoperationwithblock:^{ // i/o code svgkimage *baseicon = [settings geticonbasesvg:location]; // cpu-only code svgkimage *iconimage = [settings geticonimage:location withbasesvg:baseicon]; uiimage *svgimage = iconimage.uiimage; // converting svgkimage uiimage expensive, don't on main thread [[nsoperationqueue mainqueue] addoperationwithblock:^{ // code executed on main thread when background task finished if (svgimage) { [iconimgview setimage:svgimage]; } }]; }];
instead of directly using gcd concurrent queue, use nsoperationqueue
. set maxconcurrentoperationcount
reasonable, 4 or 8.
if can, should separate i/o pure computation. use width-restricted operation queue i/o. pure computation can use unrestricted operation queue or pure gcd for.
the reason i/o blocks. gcd detects system idle , spins worker thread , starts task queue. blocks in i/o, too, more until hits limit. then, i/o starts completing , tasks unblock. have oversubscribed system resources (i.e. cpu) because there more tasks in flight cores , using cpu instead of being blocked i/o.
pure computation tasks don't provoke problem because gcd sees system busy , doesn't dequeue more tasks until earlier ones have completed.
Comments
Post a Comment