多线程
GCD---同步/异步 ,串行/并发
1.死锁
2.延时函数(dispatch_after)
3.使用dispatch_once实现单例
4.dispatch_barrier_async
5.dispatch_group_async
enter和 leave, 然后 notify 方法通知回调
1. 线程间通信的体现
1.1个线程传递数据给另1个线程
2.在1个线程中执行完特定任务后,转到另1个线程继续执行任务
线程间通信常用方法
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait;
image.png
2. GCD 对比 NSOprationQueue
我们要明确NSOperationQueue与GCD之间的关系
GCD是面向底层的C语言的API,NSOpertaionQueue用GCD构建封装的,面向对象, 是GCD的高级抽象。
1、GCD执行效率更高,而且由于队列中执行的是由block构成的任务,这是一个轻量级的数据结构,写起来更方便
2、GCD只支持FIFO的队列,而NSOperationQueue可以通过设置最大并发数,设置优先级,添加依赖关系等调整执行顺序
3、NSOperationQueue甚至可以跨队列设置依赖关系,但是GCD只能通过设置串行队列,或者在队列内添加barrier(dispatch_barrier_async)任务,才能控制执行顺序,较为复杂
4、NSOperationQueue因为面向对象,所以支持KVO,可以监测operation是否正在执行(isExecuted)、是否结束(isFinished)、是否取消(isCanceld)
实际项目开发中,很多时候只是会用到异步操作,不会有特别复杂的线程关系管理,所以苹果推崇的且优化完善、运行快速的GCD是首选
如果考虑异步操作之间的事务性,顺序行,依赖关系,比如多线程并发下载,GCD需要自己写更多的代码来实现,而NSOperationQueue已经内建了这些支持
不论是GCD还是NSOperationQueue,我们接触的都是任务和队列,都没有直接接触到线程,事实上线程管理也的确不需要我们操心,系统对于线程的创建,调度管理和释放都做得很好。而NSThread需要我们自己去管理线程的生命周期,还要考虑线程同步、加锁问题,造成一些性能上的开销
1.可以队列组和依赖, 但是比较麻烦, 最好用 dispatch_barrier, 栅栏的方式
2.网络请求本身已经封装好是异步的了, 任务会立即完成, 但是数据还没有返回回来, 一种方式是把网络请求转为同步, 捕获正确的完成时间, 一种是使用正确的信号量
3.并发是多个任务在同一时间间隔发生的,如单CPU处理多线程,
并行是多个任务在同一时刻发生的, 如多CPU处理多线程.
4.死锁, 在主线程让主线程执行同步任务
同步和异步 , 是否开启了新的线程?
1.多个网络请求完成后执行下一步?
使用GCD的dispatch_group
每次网络请求都先dispatch_group_enter, 请求回调后再dispatch_group_leave, 这个两个必须配合使用, 两个完成之后这个 group 会自动释放, 当所有的完成之后, 会调用的dispatch_group_notifiy 方法, 通过这个 block, 拿到最终的数据
2.多个网络请求顺序执行后执行下一步
使用信号量 semaphore
每一次遍历, 都让其dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER), 这个线程会等待, 阻塞当前线程, 知道dispatch_semaphore_signal, 调用之后
3.异步操作两组数据时, 执行完第一组之后, 才能执行第二组
dispatch_barrier_async 栅栏的方法
死锁
最常见的就是 同步函数 + 主队列 的组合,本质是队列阻塞。
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"2");
});
NSLog(@"1");
// 什么也不会打印,直接报错
4.GCD执行原理?
GCD有一个底层线程池,这个池中存放的是一个个的线程。之所以称为“池”,很容易理解出这个“池”中的线程是可以重用的,当一段时间后这个线程没有被调用胡话,这个线程就会被销毁。注意:开多少条线程是由底层线程池决定的(线程建议控制再3~5条),池是系统自动来维护,不需要我们程序员来维护(看到这句话是不是很开心?) 而我们程序员需要关心的是什么呢?我们只关心的是向队列中添加任务,队列调度即可。
如果队列中存放的是同步任务,则任务出队后,底层线程池中会提供一条线程供这个任务执行,任务执行完毕后这条线程再回到线程池。这样队列中的任务反复调度,因为是同步的,所以当我们用currentThread打印的时候,就是同一条线程。
如果队列中存放的是异步的任务,(注意异步可以开线程),当任务出队后,底层线程池会提供一个线程供任务执行,因为是异步执行,队列中的任务不需等待当前任务执行完毕就可以调度下一个任务,这时底层线程池中会再次提供一个线程供第二个任务执行,执行完毕后再回到底层线程池中。
这样就对线程完成一个复用,而不需要每一个任务执行都开启新的线程,也就从而节约的系统的开销,提高了效率。在iOS7.0的时候,使用GCD系统通常只能开58条线程,iOS8.0以后,系统可以开启很多条线程,但是实在开发应用中,建议开启线程条数:35条最为合理。
block就是能够读取其它函数内部变量的函数
网友评论