进程与线程的区别
进程是资源的分配单位,线程是CPU在进程内切换的单位,简单地说进程就是任务,一个执行程序,进程之间是相互独立的,而线程处于进程空间内、多个线程共享一定空间、多个线程可以同时进行,也就是进程包含线程。
iOS中一个程序属于一个进程,是否能后台运行程序也就是是否能够进行多进程的切换。
iOS中的线程
iOS中有4中多线程方案,分别为:Ptheads
,NSThread
,GCD
与NSOperation
Ptheads
Ptheads
属于C语言框架的多线程处理方案,具有高度移植性,我们在iOS开发中基本用不到,但是RunLoop是采用此方式管理线层
NSThread
经过苹果封装后的,并且完全面向对象的,所以你可以直接操控线程对象,非常直观和方便,不过它的生命周期还是需要我们手动管理
NSThread创建线程:
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:nil];
// 启动
[thread start];
或者
[NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:nil];
如果需要获取当前线程
[NSThread currentThread]
GCD
GCD全名为Grand Central Dispatch(大中枢派发)是 Apple 开发的一个多核编程的较新的解决方法,它主要用于优化应用程序以支持多核处理器以及其他对称多处理系统,使用“词法闭包”可以将代码像对象一样传递 具有多核并行运算,自动利用多核CPU,自动管理线程生命周期的特点。
任务
线程中执行的代码块,在GCD中任务是放在Block中执行的 执行任务的方式拥有同步与异步两种方式。
同步(sync)任务能够阻塞当前线程,同时不具备开辟线程的能力
异步(async)任务不会阻塞当前线程,具备开辟线程的能力,但并不是异步就能开辟线程,这一点非常重要(如:在异步方式在主线程中执行)
//异步方式在主线程中执行
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"在当前主线程中执行");
});
// 同步任务
dispatch_sync(queue, ^{
// 这里放同步执行任务代码
});
// 异步任务
dispatch_async(queue, ^{
// 这里放异步执行任务代码
});
这里的queue则为需要传入的队列
队列
队列相对于同步与异步执行方式而言的,用于存放任务,分为串行队列,并发队列。
串行队列(Serial Dispatch Queue)遵循先进先出的原则(FIFO)即新任务总是被插入到队列的末尾,而读取任务的时候总是从队列的头部开始读取。
并发队列(Concurrent Dispatch Queue)同样遵循先进先出的原则,不过并发队列可以让多个任务并发(同时)执行
全局队列与主队列
全局队列是相对于并发队列而言的,在并发队列中GCD 默认提供了全局并发队列(Global Dispatch Queue)
主队列是相对于串行队列而言的,在串行队列中GCD 提供了的一种特殊的串行队列:主队列(Main Dispatch Queue)
创建队列
//串行队列
dispatch_queue_t searilQueue = dispatch_queue_create("searilQueue", DISPATCH_QUEUE_SERIAL);
//并发队列
dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
//全局队列
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//主队列
dispatch_get_main_queue()
串行队列与并发队列通过dispatch_queue_create()
创建,需要传入两个参数,第一个参数表示队列的唯一标识符,可为空;第二个参数用来识别是串行队列还是并发队列。其中DISPATCH_QUEUE_SERIAL
表示串行队列,DISPATCH_QUEUE_CONCURRENT
表示并发队列
全局队列通过dispatch_get_global_queue()
创建,需要传入两个参数,第一个为队列优先级;第二个直接传0即可。其中队列优先级分为:
#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_QUEUE_PRIORITY_DEFAULT
即可
任务与队列组合
当同步异步与串行并行队列组合时会有8种不同的组合方式:
- 同步串行队列
- 同步并发队列
- 异步串行队列
- 异步并发队列
- 同步主队列 (会导致线程死锁)
- 异步主队列
- 同步全局队列
- 异步全局队列
这几种组合的区别:
当然GCD的使用不是简单地这么几种,还有组队列,信号量与栏栅操作等,所有这些操作的使用可以点击这里查看用法
NSOperation
NSOperation是苹果最早提供给开发者使用的一套多线程解决方案,是基于GCD更高一层的封装,但是比GCD更简单易用、代码可读性也更高
NSOperation是个抽象类,并不能封装任务,它拥有三个子类NSInvocationOperation
,NSBlockOperation
以及定义继承自NSOperation
的子类,我们可以使用这三个子类进行任务的封装,定义继承自NSOperation的子类的方式并不经常使用这里就不再讲述
NSInvocationOperation
// 创建NSInvocationOperation对象
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
[op start];
NSBlockOperation
/ 创建NSBlockOperation对象
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
// 在主线程
NSLog(@"------%@", [NSThread currentThread]);
}];
[op start];
需要注意的是NSBlockOperation
还有一个方法:addExecutionBlock:
,通过这个方法可以给 Operation
添加多个执行 Block
,这样 Operation
中的任务 会并发执行,它会 在主线程和其它的多个线程 执行这些任务:
NSBlockOperation * blockOperation = [[NSBlockOperation
blockOperationWithBlock:^{
NSLog(@"1在第%@个线程",[NSThread currentThread]);
}];
[blockOperation addExecutionBlock:^{
NSLog(@"2在第%@个线程",[NSThread currentThread]);
}];
[blockOperation addExecutionBlock:^{
NSLog(@"3在第%@个线程",[NSThread currentThread]);
}];
除此之外NSOperation还可以为线程添加依赖关系,设置最大并发数来控制线程,可以对线程进行取消与挂起的操作。
其中线程添加依赖关系GCD中没有封装好的方法,实现起来较为复杂(需要信号量加锁控制),同时GCD也没有对线程取消的功能,这在NSOperation中都可以实现,具体用法可以点击这里