唐山专门做网站,国内做视频网站需要啥,上海整站优化,自己做h5怎么做对GCD的一些理解和实践GCD GCD#xff0c;全程Grand Central Dispatch#xff0c;是苹果为了多核并行提出的解决方案。它是使用C语言实现#xff0c;但是由于用了block来处理回调#xff0c;所以使用起来十分方便。并且GCD会自动管理线程的生命周期#xff0c;不需要我们去…对GCD的一些理解和实践 GCD GCD全程Grand Central Dispatch是苹果为了多核并行提出的解决方案。它是使用C语言实现但是由于用了block来处理回调所以使用起来十分方便。并且GCD会自动管理线程的生命周期不需要我们去管理。 任务和队列 GCD中有两个重要的概念任务和队列。 1、任务就是我们想要处理的事情任务可以分为同步执行和异步执行 同步sync使用dispatch_sync(dispatch_queue_t queue, dispatch_block_t block) 创建同步执行任务时会阻塞当前线程等待block执行完毕返回。然后当前线程才会继续执行下去。 异步async使用dispatch_async(dispatch_queue_t queue, dispatch_block_t block)创建异步任务不会阻塞当前线程任务创建后立即返回线程往下执行。 2、队列存放任务并将任务由先入先出地派发出去。分为串行队列和并行队列 串行队列Serial queue队列中的任务根据创建顺序先入先出地执行等待上一个任务执行完毕后才会执行下一个任务有严格的执行先后顺序。 并行队列Concurrent queue队列会根据先后顺序将任务派发出去并行执行。所有的任务几乎都是一起执行的。不过需要注意GCD 会根据系统资源控制并行的数量所以如果任务很多它并不会让所有任务同时执行。有一个表可以大体说明任务和队列之间的配合使用 串行队列并行队列同步执行任务当前线程一个一个执行当前线程一个一个执行异步执行任务另开线程一个一个执行开很多线程一起执行 下面是任务和队列的使用演示 /*** 串行队列中的任务会等待正在执行的任务执行结束排队执行*/dispatch_queue_t serial_queue dispatch_queue_create(serial.queue, DISPATCH_QUEUE_SERIAL);//主队列dispatch_queue_t mainQueue dispatch_get_main_queue();/*** 并行不等待正在执行的任务的处理结果可以并发执行多个任务*/dispatch_queue_t concurrent_queue dispatch_queue_create(concurrent.queue, DISPATCH_QUEUE_CONCURRENT);//全局队列dispatch_queue_t globalQueue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);//在串行队列中创建几个同步任务在主线程顺序执行dispatch_sync(serial_queue, ^{NSLog(task a ,thread:%,[NSThread currentThread]);});dispatch_sync(serial_queue, ^{NSLog(task b ,thread:%,[NSThread currentThread]);});dispatch_sync(serial_queue, ^{NSLog(task c ,thread:%,[NSThread currentThread]);});//在串行队列中创建几个异步任务在主线程顺序执行dispatch_sync(serial_queue, ^{NSLog(task aa ,thread:%,[NSThread currentThread]);});dispatch_sync(serial_queue, ^{NSLog(task bb ,thread:%,[NSThread currentThread]);});dispatch_sync(serial_queue, ^{NSLog(task cc ,thread:%,[NSThread currentThread]);});//在串行队列中创建几个异步任务另开1个线程顺序执行dispatch_async(serial_queue, ^{NSLog(task 1 ,thread:%,[NSThread currentThread]);});dispatch_async(serial_queue, ^{NSLog(task 1 ,thread:%,[NSThread currentThread]);});dispatch_async(serial_queue, ^{NSLog(task 1 ,thread:%,[NSThread currentThread]);});//在并队列中创建几个异步任务另开多个线程同时执行dispatch_async(concurrent_queue, ^{NSLog(task 11 ,thread:%,[NSThread currentThread]);});dispatch_async(concurrent_queue, ^{NSLog(task 22 ,thread:%,[NSThread currentThread]);});dispatch_async(concurrent_queue, ^{NSLog(task 33 ,thread:%,[NSThread currentThread]);}); 任务组和栅栏 有时候当我们想要为多个任务添加依赖关系的时候就可以使用任务组dispatch_group和dispatch_barrier。 任务组是将若干个任务放在一个group 中这些任务可以在同一队列也可以在不同队列然后用dispatch_group_notify()和dispatch_group_wait()对任务组中任务的完成进行处理。 1、dispatch_group_notify()中的任务会在group中多有任务执行完毕后执行 dispatch_group_t group dispatch_group_create();/*** group中所有任务任务执行完毕后执行dispatch_group_notify中的任务*/dispatch_group_async(group, serial_queue, ^{sleep(2);NSLog(serial_queue1);});dispatch_group_async(group, serial_queue, ^{sleep(2);NSLog(serial_queue2);});dispatch_group_async(group, concurrent_queue, ^{sleep(2);NSLog(concurrent_queue1);});dispatch_group_notify(group, dispatch_get_main_queue(), ^{NSLog(return main queue);}); 2、dispatch_group_wait()中可传入一个给定时间如果在等待时间结束前group所有任务执行完毕则返回0否则返回非0这个函数是一个同步任务 /*** dispatch_group_wait给定一个时间如果在等待时间结束前group所有任务执行完毕则返回0否则返回非0这个函数是一个同步任务*/dispatch_group_async(group, serial_queue, ^{sleep(3);NSLog(serial_queue1);});dispatch_group_async(group, serial_queue, ^{sleep(2);NSLog(serial_queue2);});dispatch_group_async(group, concurrent_queue, ^{sleep(3);NSLog(concurrent_queue1);});long i dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 6));NSLog(-- %ld --,i);dispatch_group_async(group, concurrent_queue, ^{NSLog(finish all);}); 3、可以使用dispatch_group_enter()和dispatch_group_leave()来添加任务组的任务两者必须要成对出现两个函数之间的代码便是要加入任务住的任务 /*** 使用dispatch_group_enter和dispatch_group_leave添加组任务,两者必须要成对出现*/dispatch_group_enter(group);sleep(2);NSLog(1);dispatch_group_leave(group);dispatch_group_enter(group);dispatch_async(concurrent_queue, ^{sleep(3);NSLog(2);dispatch_group_leave(group);});dispatch_group_enter(group);sleep(2);NSLog(3);dispatch_group_leave(group);long i dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 6));NSLog(-- %ld --,i);dispatch_group_async(group, concurrent_queue, ^{NSLog(finish all);}); 栅栏是将一个队列中的任务分割成两部分在栅栏任务之前添加的任务全部执行完毕后单独执行栅栏任务执行完毕后再继续执行后面的任务。栅栏必须单独执行不能与其他任务并发执行因此栅栏只对并发队列有意义。栅栏只有等待当前队列所有并发任务都执行完毕后才会单独执行待其执行完毕再按照正常的方式继续向下执行。 dispatch_queue_t concurrent_queue dispatch_queue_create(concurrent.queue, DISPATCH_QUEUE_CONCURRENT);dispatch_async(concurrent_queue, ^{sleep(2);NSLog(1);});dispatch_async(concurrent_queue, ^{sleep(2);NSLog(2);});dispatch_async(concurrent_queue, ^{sleep(2);NSLog(3);});dispatch_barrier_async(concurrent_queue, ^{sleep(2);NSLog(barrier);});dispatch_async(concurrent_queue, ^{sleep(2);NSLog(finish1);});dispatch_async(concurrent_queue, ^{NSLog(finish2);}); 重复执行dispatchApply 和 单次执行dispatch_once dispatch_apply()是将一个任务提交到队列中重复执行并行或者串行由队列决定dispatch_apply会阻塞当前线程等到所有任务完成后返回 dispatch_queue_t concurrent_queue dispatch_queue_create(concurrent.queue, DISPATCH_QUEUE_CONCURRENT);dispatch_apply(5, concurrent_queue, ^(size_t index) {sleep(1);NSLog(index:%zu,index);});NSLog(finish); dispatch_once()确保block内代码在整个应用运行期间只执行一次 //确保block内代码在整个应用运行期间只执行一次static dispatch_once_t onceToken;dispatch_once(onceToken, ^{NSLog(just run once in application);}); 线程同步、信号量和线程死锁 多线程处理经常需要考虑到资源抢占的问题比如经典的购票问题写数据库等问题。处理问题的办法有很多下面介绍最简单的两种做法加上同步锁或者用信号量来解决。 同步锁每当有线程访问锁里的资源时会将此部分锁住拒绝其他线程访问。直到占用的线程推出后才解锁允许其他资源访问。 //同步锁对block内的代码加锁,同一时间内只允许一个线程访问synchronized(self) {NSLog(lock);}; 信号量dispatch_semaphore一开始设置信号的总量然后用dispatch_semaphore_wait()和dispatch_semaphore_signal()来管理信号量达到控制线程访问的目的 //信号量dispatch_semaphoredispatch_group_t group dispatch_group_create();//设置总信号量dispatch_semaphore_t semaphore dispatch_semaphore_create(10);for (int i 0; i100; i) {//设置等待信号如果此时信号量大于0那么信号量减一并继续往下执行//如果此时信号量小于0会一直等待直到超时//如果超时返回非零成功执行返回0dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC*50));dispatch_group_async(group, concurrent_queue, ^{sleep(1);NSLog(%d,i);//发送信号让信号量加一dispatch_semaphore_signal(semaphore);});}dispatch_group_notify(group, concurrent_queue, ^{NSLog(finish);}); GCD尽管使用起来非常方便但是如果使用不当也活造成一些麻烦下面列举几个会造成线程死锁的场合 //在并行队列中在当前队列调用dispatch_sync并传入当前队列执行并不会造成deadlock。dispatch_sync会阻塞当前线程但是由于队列是并行执行所以block中的任务会马上执行后返回。
- (void)syncAndConcurrentQueue {dispatch_queue_t queue dispatch_queue_create(concurrent.queue, DISPATCH_QUEUE_CONCURRENT);dispatch_sync(queue, ^{NSLog(Jump to concurrent.queue! ,thread:%,[NSThread currentThread]);dispatch_sync(queue, ^{sleep(3);NSLog(success6 ,thread:%,[NSThread currentThread]);});NSLog(return);});
}//在串行队列中在当前队列调用dispatch_sync并传入当前队列执行会造成deadlock。 dispatch_sync会阻塞当前线程等待block中的任务执行完之后再继续执行但是由于队列是串行执行block中的任务放在最后所以永远没有机会执行线程死锁
- (void)synAndSerialQueue {dispatch_queue_t queue dispatch_queue_create(serial.queue, DISPATCH_QUEUE_SERIAL);dispatch_async(queue, ^{NSLog(Jump to serial.queue!);dispatch_sync(queue, ^{NSLog(success);});NSLog(return);});
}//任务1会阻塞主线程直到block中执行完毕返回任务二在主线程添加了了一个同步任务阻塞当前线程知道任务执行完毕返回而任务2没有机会被执行。造成两条线程死锁。
- (void)recycle {dispatch_queue_t concurrent_queue dispatch_queue_create(concurrent.queue, DISPATCH_QUEUE_CONCURRENT);//任务1dispatch_sync(concurrent_queue, ^{NSLog(jump to concurrent queue);//任务2dispatch_sync(dispatch_get_main_queue(), ^{NSLog(return main queue);});});
} 总结 以上是使用GCD的一些心得GCD使用起来尽管十分便利但是在处理一些场景比如取消任务时候会很麻烦所以实现简单功能的时候推荐使用GCD如果功能复杂的话建议使用NSOperation和NSOperationQueueNSOperationQueue的底层也是由GCD实现的完全面向对象所以使用起来更好理解。下次有空讲讲NSOperation和NSOperationQueue。以上代码demo地址https://github.com/GarenChen/GCDDemo 原本文链接http://www.cnblogs.com/GarenChen/p/5858280.html 转载于:https://www.cnblogs.com/jx451578429/p/5893373.html