一、进程编程
进程是指在系统中正在运行的一个应用程序,每一个进程之间是独立的,每一个进程均运行在其专用且受保护的内存空间内;网络
若是咱们把CPU比做一个工厂,那么进程就比如工厂的车间,一个工厂有好多个车间,每一个车间都在进行不一样的工做,它们之间是独立互不干扰的。多线程
二、线程并发
线程是进程的基本执行单元,一个进程的全部任务都在线程中执行;一个进程要想执行任务,必须得有线程(每一个进程至少要有1条线程);app
线程就比如车间里的工人,一个车间里能够有好多工人(一个进程能够包括多个线程),他们协同完成一个任务;异步
多线程是一个比较轻量级的方法来实现单个应用程序内多个代码执行路径。async
一个进程中能够开启多条线程,每条线程能够并行(同时)执行不一样的任务,能够提升程序的执行效率;函数
原理:同一时间,CPU只能处理1条线程,只有1条线程在工做(执行);多线程并发(同时)执行,实际上是CPU快速地在多条线程之间调度(切换)若是CPU调度线程的时间足够快,就形成了多线程并发执行的假象。oop
优缺点:
性能
多线程的优势:
(1)能适当提升程序的执行效率
(2)能适当提升资源利用率(CPU、内存利用率)
多线程的缺点:
(1)开启线程须要占用必定的内存空间(默认状况下,主线程占用1M,子线程占用512KB),若是开启大量的线程,会占用大量的内存空间,下降程序的性能
线程越多,CPU在调度线程上的开销就越大
(2)程序设计更加复杂:好比线程之间的通讯、多线程的数据共享
iOS中几种多线程实现:
一、Thread
二、Cocoa operations
三、GCD(Grand Central Dispatch)(iOS4 以后)
一、NSThread
(1)NSThread有两种建立方式:
- (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument;
+ (void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument;
//实例方法 thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadAction:) object:nil];
//启动线程 [thread start]; //类方法 [NSThread detachNewThreadSelector:@selector(threadAction:) toTarget:self withObject:nil];
selector :线程执行的方法,selector只能有一个参数,且不能有返回值;
target :selector消息发送的对象;
object :传输给target的惟一参数,也能够是nil;
两种建立方式的不一样:
类方法一调用就会当即建立一个线程来作事情;
实例方法要直到咱们手动调用 start 启动线程时才会真正去建立线程;
(2)不显式建立线程的方法(间接建立):
利用NSObject的方法 performSelectorInBackground:withObject:来建立;
//隐含产生新线程
[myView performSelectorInBackground:@selector(Action:) withObject:nil];
(3)NSThread相关属性及方法:
@property (copy) NSString *name; // 获取/设置线程的名字
+ (NSThread *)currentThread; // 获取当前线程的线程对象
+ (void)sleepForTimeInterval:(NSTimeInterval)ti; // 线程休眠(秒)
+ (void)sleepUntilDate:(NSDate *)date; // 线程休眠,指定具体什么时间休眠
+ (void)exit; // 退出线程(线程对象销毁,销毁后就不能再次启动线程,不然程序会崩溃)
二、NSOperation
(1)NSInvocationOperation
NSInvocationOperation的建立:
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(operationAction) object:nil];//object能够带一个参数
//启动线程,默认是不启动 [operation start];
- (void)operationAction{}
参数和NSTread同样。
(2)NSBlockOperation
NSBlockOperation 是 NSOperation 类的另一个系统预约义的子类,咱们能够用它来封装一个或多个 block。
通常来讲,有如下两个场景咱们会优先使用 NSBlockOperation 类:
当咱们在应用中已经使用了 Operation Queues 且不想建立 Dispatch Queues 时,NSBlockOperation 类能够为咱们的应用提供一个面向对象的封装;
咱们须要用到 Dispatch Queues 不具有的功能时,好比须要设置 operation 之间的依赖关系、使用 KVO 观察 operation 的状态变化等;
NSBlockOperation的建立:
咱们可使它并发执行,经过使用addExecutionBlock方法添加多个Block,这样就能使它在主线程和其它子线程中工做。
- (NSBlockOperation*)blockOperation{ NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"block1,mainThread:%@,currebtThread:%@",[NSThread mainThread],[NSThread currentThread]); }]; [blockOperation addExecutionBlock:^{ NSLog(@"block2,mainThread:%@,currebtThread:%@",[NSThread mainThread],[NSThread currentThread]); NSLog(@"Finish block2"); }]; [blockOperation addExecutionBlock:^{ NSLog(@"block3,mainThread:%@,currebtThread:%@",[NSThread mainThread],[NSThread currentThread]); NSLog(@"Finish block3"); }]; return blockOperation; }
(3)NSOperationQueue
一个NSOperation对象能够经过调用start方法来执行任务,默认是同步执行的;也能够将NSOperation添加到一个NSOperationQueue(操做队列)中去执行,并且是异步执行的。
一、NSOperation方法及属性:
// 设置线程的最大并发数 @property NSInteger maxConcurrentOperationCount; // 线程完成后调用的Block @property (copy) void (^completionBlock)(void); // 取消线程 - (void)cancel;
二、建立一个操做队列:
NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
三、添加NSOperation到NSOperationQueue中:
//添加一个operation [operationQueue addOperation:operation]; //添加一组operation NSArray *operations = [NSArray arrayWithObjects:@"",@"", nil]; [operationQueue addOperations:operations waitUntilFinished:NO]; //添加一个block形式的operation [operationQueue addOperationWithBlock:^() { NSLog(@"blockOperation:%@", [NSThread currentThread]); }];
四、设置NSOperation的依赖对象
(1)当某个NSOperation对象依赖于其它NSOperation对象的完成时,就能够经过addDependency方法添加一个或者多个依赖的对象,只有全部依赖的对象都已经完成操做,当前NSOperation对象才会开始执行操做。经过removeDependency方法来删除依赖对象。
以下代码:operation1依赖operation2,意思为先执行operation2,operation2完成后继续执行operation1;
[operation2 addDependency:operation1];
删除依赖对象,删除后则不存在依赖关系;以下代码:
[operation2 removeDependency:operation1];
(2)没有设置依赖关系的状况下:(默认)
NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init]; NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^(){ NSLog(@"执行第1次操做:%@", [NSThread currentThread]); }]; NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^(){ NSLog(@"执行第2次操做:%@", [NSThread currentThread]); }]; [operationQueue addOperation:operation1]; [operationQueue addOperation:operation2];
打印:
由打印信息能够看出,默认是按顺序进行的;
(3)设置依赖关系的状况下:
NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init]; NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^(){ NSLog(@"执行第1次操做:%@", [NSThread currentThread]); }]; NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^(){ NSLog(@"执行第2次操做:%@", [NSThread currentThread]); }]; [operation1 addDependency:operation2]; [operationQueue addOperation:operation1]; [operationQueue addOperation:operation2];
打印:
能够看出程序先执行operation2,后执行operation1。
若是要解除依赖关系,则:
[operation1 removeDependency:operation2];
注意:在NSOperationQueue类中,咱们可使用cancelAllOperations方法取消全部的线程。这里须要注意一下,不是执行cancelAllOperations方法时就会立刻取消,是等当前队列执行完,下面的队列不会再执行。
三、 GCD(Grand Central Dispatch)
GCD 是Apple公司开发的一种技术,异步执行任务的技术之一,它旨在优化多核环境中的并发操做并取代传统多线程的编程模式;在Mac OS X 10.6和IOS 4.0以后开始支持GCD。
工做原理:让程序平行排队的特定任务,根据可用的处理资源,安排他们在任何可用的处理器核心上执行任务。
GCD中的FIFO(First In First Out)队列称为dispatch queue,它能够保证先进来的任务先获得执行;
Dispatch Queue分三种:
(1)Main queue:main dispatch queue 是一个全局可用的串行队列,在应用程序的主线程上执行任务。此队列的任务和应用程序的主循环(run loop)要执行的事件源交替执行。由于运行在应用程序的主线程,main queue常常用来做为应用程序的一个同步点。
(2)Serial quque: 又称private dispatch queue(私有调度队列),每次运行一个任务,能够添加多个,执行次序FIFO,通常用再对特定资源的同步访问上。咱们能够根据须要建立任意数量的串行队列,每个串行队列之间是并发的。
(3)Concurrent queue: 又称为global dispatch queue,能够并发地执行多个任务,可是执行完成的顺序是随机的.
使用方法:
(1)dispatch_async
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
async代表异步运行,除了async,还有sync(同步),delay(延时);
block表明的是你要作的事情;
queue则是你把任务交给谁来处理了;
dispatch_async 这个函数是异步的,这就意味着它会当即返回而无论block是否运行结束。所以,咱们能够在block里运行各类耗时的操做(如网络请求) 而同时不会阻塞UI线程。
举个例子看看它的实际用法:(下载一张图片)
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. imageView = [[UIImageView alloc] initWithFrame:self.view.bounds]; [self.view addSubview:imageView]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSURL *url = [NSURL URLWithString:@"http://e.hiphotos.baidu.com/image/h%3D200/sign=5dafb2a3586034a836e2bf81fb1249d9/d31b0ef41bd5ad6e194e5f4885cb39dbb7fd3cd8.jpg"]; NSData *data = [NSData dataWithContentsOfURL:url]; UIImage *image = [[UIImage alloc] initWithData:data]; if (data) { dispatch_async(dispatch_get_main_queue(), ^{ imageView.image = image; }); } }); }
运行:
比起NSThread和NSOperation用法是否是简单多了。
系统给每个应用程序提供了四个concurrent dispatch queues,这四个并发调度队列是全局的,它们只有优先级的不一样;
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(@"print");
});
打印:
(3)dispatch_barrier_async
dispatch_barrier_async是在前面的任务执行结束后它才执行,并且它后面的任务等它执行完成以后才会执行;
dispatch_queue_t queue = dispatch_queue_create("1", DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue, ^{ [NSThread sleepForTimeInterval:2]; NSLog(@"queue1"); }); dispatch_async(queue, ^{ [NSThread sleepForTimeInterval:4]; NSLog(@"queue2"); }); dispatch_barrier_async(queue, ^{ NSLog(@"dispatch_barrier_async"); [NSThread sleepForTimeInterval:4]; }); dispatch_async(queue, ^{ [NSThread sleepForTimeInterval:2]; NSLog(@"queue3"); });
打印:
(4)dispatch_apply
执行某个代码片断几回。
dispatch_apply(2, globalQ, ^(size_t index) {
// 执行2次
});
(5)dispatch_suspend/dispatch_resume