NSThread/NSOperation/GCD的优缺点总结

2018-03-12  本文已影响0人  私人云笔记_骁勇波波

转自:http://blog.csdn.net/nathan1987_/article/details/50436132

•NSThread:

–优点:NSThread 比其他两个轻量级,使用简单

–缺点:需要自己管理线程的生命周期、线程同步、加锁、睡眠以及唤醒等。线程同步对数据的加锁会有一定的系统开销

[objc] view plain copy

//创建线程方法1  

NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(threadAction:) object:nil];  

[thread start];//开启子线程  

[thread cancel];//取消子线程  

//创建线程方法2-立即在线程中执行任务  

[NSThread detachNewThreadSelector:@selector(threadAction:) toTarget:self withObject:nil];  

//创建线程方法3-在后台子线程中执行任务  

[self performSelectorInBackground:@selector(threadAction:) withObject:nil];  

-(void)threadAction:(id*)sender{  

@autoreleasepool {  

//子线程中通知主线程通常使用以下两种办法  

// [self.imageview performSelectorOnMainThread:@selector(updateView:) withObject:nil waitUntilDone:YES];  

// [self.imageview performSelector:@selector(updateView:) onThread:[NSThread mainThread] withObject:nil waitUntilDone:YES];  

    }  

}  

线程间通讯

线程下载完图片后怎么通知主线程更新界面呢?

performSelectorOnMainThread是NSObject的方法,除了可以更新主线程的数据外,还可以更新其他线程的

两种锁,一种NSCondition ,一种是:NSLock

 // 锁对象   

    theLock = [[NSLock alloc] init];   

    ticketsCondition = [[NSCondition alloc] init];

        // 上锁   

//      [ticketsCondition lock];   

        [theLock lock];   

//中间写代码

  //开锁

//      [ticketsCondition unlock]; 

        [theLock unlock]; 

可以通过[ticketsCondition signal]; 发送信号的方式,在一个线程唤醒另外一个线程的等待。

NSCondition的wait其实就是在线程内等待一个信号量, 信号量出现时就继续, 否则一直等下去

也可以用- (BOOL)waitUntilDate:(NSDate *)limit; 

这个在给定的时间到达时仍未有信号量出现, 就自动继续了.

如果用户给出信号量来触发继续的话, 会返回1

如果超时触发继续, 返回0

theLock = [[NSLock alloc] init];   

    // 锁对象   

    ticketsCondition = [[NSCondition alloc] init];   

        [ticketsCondition lock];   

        [NSThread sleepForTimeInterval:3];   

        [ticketsCondition signal];   //唤醒另一个线程

        [ticketsCondition unlock];   

        // 上锁   

        [ticketsCondition lock];   

        [ticketsCondition wait];   

        [theLock lock];   

     //要做的事情

        [theLock unlock];   

        [ticketsCondition unlock];  

其他同步

我们可以使用指令 @synchronized 来简化 NSLock的使用,这样我们就不必显示编写创建NSLock,加锁并解锁相关代码。

    @synchronized(anObj) 

    { 

        // Everything between the braces is protected by the @synchronized directive. 

    } 

还有其他的一些锁对象,

比如:循环锁NSRecursiveLock,条件锁NSConditionLock,分布式锁NSDistributedLock等等,可以自己看官方文档学习

•NSOperation:

–不需要关心线程管理,数据同步的事情,可以把精力放在自己需要执行的操作上

–NSOperation是面向对象的

//NSOperationQueue

//两种操作-(操作本身跟多线程关系不大)

//NSInvocationOperation

//NSBlockOperation

NSInvocationOperation *inop = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(inopAction:) object:nil];

//[inop start];

NSBlockOperation *blop = [NSBlockOperation blockOperationWithBlock:^{

@autoreleasepool { NSLog(@"blop"); }   }];

//队列

NSOperationQueue *queue = [[NSOperationQueue alloc]init];

//1的话顺序执行

//同时执行最大操作数

queue.maxConcurrentOperationCount = 3;

//依赖关系

[inop addDependency:blop];//blop执行完,才能执行inop

//向队列添加操作

[queue addOperation:inop];

[queue addOperation:blop];

-(void)inopAction:(id)sender{

@autoreleasepool { NSLog(@"inop"); }

}

关于并发数

(1)并发数:同时执⾏行的任务数.比如,同时开3个线程执行3个任务,并发数就是3

(2)最大并发数:同一时间最多只能执行的任务的个数。

(3)最⼤大并发数的相关⽅方法

- (NSInteger)maxConcurrentOperationCount;

- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;

说明:如果没有设置最大并发数,那么并发的个数是由系统内存和CPU决定的,可能内存多久开多一点,内存少就开少一点。

注意:num的值并不代表线程的个数,仅仅代表线程的ID。

提示:最大并发数不要乱写(5以内),不要开太多,一般以2~3为宜,因为虽然任务是在子线程进行处理的,但是cpu处理这些过多的子线程可能会影响UI,让UI变卡。

•GCD:

–Grand Central Dispatch是由苹果开发的一个多核编程的解决方案。iOS4.0+才能使用,是替代NSThread, NSOperation的高效和强大的技术

–GCD是基于C语言的

GCD的工作原理是:让程序平行排队的特定任务,根据可用的处理资源,安排他们在任何可用的处理器核心上执行任务。

一个任务可以是一个函数(function)或者是一个block。 GCD的底层依然是用线程实现,不过这样可以让程序员不用关注实现的细节。

GCD中的FIFO队列称为dispatch queue,它可以保证先进来的任务先得到执行

dispatch queue分为下面三种:

Serial     

又称为private dispatch queues,同时只执行一个任务。Serial queue通常用于同步访问特定的资源或数据。当你创建多个Serial queue时,虽然它们各自是同步执行的,但Serial queue与Serial queue之间是并发执行的。

Concurrent

又称为global dispatch queue,可以并发地执行多个任务,但是执行完成的顺序是随机的。

Main dispatch queue

它是全局可用的serial queue,它是在应用程序主线程上执行任务的。

The main queue: 与主线程功能相同。实际上,提交⾄至main queue的任务会在主线程中执⾏行。main queue可以调⽤用dispatch_get_main_queue()来获得。因为mainqueue是与主线程相关的,所以这是⼀一个串⾏行队列。

Global queues: 全局队列是并发队列,并由整个进程共享。进程中存在三个全局队列:⾼高、中(默认)、低、后台四个优先级队列。可以调⽤用dispatch_get_global_queue函数传⼊入优先级来访问队列。优先级:

#define DISPATCH_QUEUE_PRIORITY_HIGH 2

#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0

#define DISPATCH_QUEUE_PRIORITY_LOW (-2)

#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN

dispatch_sync(),同步添加操作。等待添加进队列里面的操作完成之后再继续执行。调用以后等到block执行完以后才返回 ,dispatch_sync()会阻塞当前线程。

dispatch_async ,异步添加进任务队列,调用以后立即返回,它不会做任何等待

在多线程开发当中,程序员只要将想做的事情定义好,并追加到DispatchQueue(派发队列)当中就好了。

派发队列分为两种,一种是串行队列(SerialDispatchQueue),一种是并行队列(ConcurrentDispatchQueue)。

一个任务就是一个block,比如,将任务添加到队列中的代码是:

1 dispatch_async(queue, block);

当给queue添加多个任务时,如果queue是串行队列,则它们按顺序一个个执行,同时处理的任务只有一个。

当queue是并行队列时,不论第一个任务是否结束,都会立刻开始执行后面的任务,也就是可以同时执行多个任务。

但是并行执行的任务数量取决于XNU内核,是不可控的。比如,如果同时执行10个任务,那么10个任务并不是开启10个线程,线程会根据任务执行情况复用,由系统控制。

延时的实现

[objc] view plain copy

 //第一种NSThread延时  

[NSThread sleepForTimeInterval:3];//延时3秒-阻塞主线程  

//第二种  

[self performSelector:@selector(dosth) withObject:nil afterDelay:2];//延时3秒执行,不会阻塞主线程  

//第三种GCD 3秒回到主线程执行 不会阻塞主线程  

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(33 * NSEC_PER_SEC)),  

dispatch_get_main_queue(), ^{NSLog(@"第三种");} );  

//第四种 GCD  

dispatch_queue_t qq = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);  

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)4*NSEC_PER_SEC), qq, ^{  

NSLog(@"第四种");  

    });  

-(void)dosth{  

NSLog(@"第二种");  

}  

dispatch_barrier_async的使用

dispatch_barrier_async是在前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行

dispatch_group_async的使用

dispatch_group_async可以实现监听一组任务是否完成,完成后得到通知执行其他的操作。这个方法很有用,比如你执行三个下载任务,当三个任务都下载完成后你才通知界面说完成的了。

[objc] view plain copy

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);  

dispatch_group_t group = dispatch_group_create();  

dispatch_group_async(group, queue, ^{  

[NSThread sleepForTimeInterval:1];  

NSLog(@"group1");  

});  

dispatch_group_async(group, queue, ^{  

[NSThread sleepForTimeInterval:2];  

NSLog(@"group2");  

});  

dispatch_group_async(group, queue, ^{  

[NSThread sleepForTimeInterval:3];  

NSLog(@"group3");  

});  

dispatch_group_notify(group, dispatch_get_main_queue(), ^{  

NSLog(@"updateUi");  

});  

dispatch_release(group);  

[objc] view plain copy

//重复执行  

//放到全局队列才执行  

dispatch_apply(10, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t t) {  

NSLog(@"重复执行,%ld",t);  

  });  

Operation、GCD对比:

优点:不需要关心线程管理,数据同步的事情。

两者区别:

NSOperationQueue可以方便的管理并发、NSOperation之间的优先级。

GCD主要与block结合使用。代码简洁高效

1. 性能:GCD更接近底层,而NSOperationQueue则更高级抽象,所以GCD在追求性能的底层操作来说,是速度最快的。这取决于使用Instruments进行代码性能分析,如有必要的话

2. 从异步操作之间的事务性,顺序行,依赖关系。GCD需要自己写更多的代码来实现,而NSOperationQueue已经内建了这些支持

3. 如果异步操作的过程需要更多的被交互和UI呈现出来,NSOperationQueue会是一个更好的选择。底层代码中,任务之间不太互相依赖,而需要更高的并发能力,GCD则更有优势

上一篇下一篇

猜你喜欢

热点阅读