iOS的三种多线程技术
以上这三种编程方式从上到下,抽象度层次是从低到高的,抽象度越高的使用越简单,也是Apple最推荐使用的,在项目中很多框架技术分别使用了不同多线程技术。
2.三种多线程技术的对比
什么是GCD?
Grand Central Dispatch或者GCD,是一套低层API,提供了一种新的方法来进行并发程序编写。从基本功能上讲,GCD有点像NSOperationQueue,他们都允许程序将任务切分为多个单一任务然后提交至工作队列来并发地或者串行地执行。GCD比之NSOpertionQueue更底层更高效,并且它不是Cocoa框架的一部分。
除了代码的平行执行能力,GCD还提供高度集成的事件控制系统。可以设置句柄来响应文件描述符、mach ports(Mach port 用于 OS X上的进程间通讯)、进程、计时器、信号、用户生成事件。这些句柄通过GCD来并发执行。
GCD的API很大程度上基于block,当然,GCD也可以脱离block来使用,比如使用传统c机制提供函数指针和上下文指针。实践证明,当配合block使用时,GCD非常简单易用且能发挥其最大能力。
你可以在Mac上敲命令“man dispatch”来获取GCD的文档。
Dispatch Queues
GCD的基本概念就是dispatch queue。dispatch queue是一个对象,它可以接受任务,并将任务以先到先执行的顺序来执行。dispatch queue可以是并发的或串行的。并发任务会像NSOperationQueue那样基于系统负载来合适地并发进行,串行队列同一时间只执行单一任务。
GCD中有三种队列类型:
- The main queue: 与主线程功能相同。实际上,提交至main queue的任务会在主线程中执行。main queue可以调用dispatch_get_main_queue()来获得。因为main queue是与主线程相关的,所以这是一个串行队列。
- Global queues: 全局队列是并发队列,并由整个进程共享。进程中存在三个全局队列:高、中(默认)、低三个优先级队列。可以调用dispatch_get_global_queue函数传入优先级来访问队列。
- 用户队列: 用户队列 (GCD并不这样称呼这种队列, 但是没有一个特定的名字来形容这种队列,所以我们称其为用户队列) 是用函数
dispatch_queue_create
创建的队列. 这些队列是串行的。正因为如此,它们可以用来完成同步机制, 有点像传统线程中的mutex。
- Dispatch Queues的生成可以有这几种方式:
- //手动创建队列 (串行)
- 1. dispatch_queue_t queue = dispatch_queue_create("com.dispatch.serial", DISPATCH_QUEUE_SERIAL); //生成一个串行队列,队列中的block按照先进先出(FIFO)的顺序去执行,实际上为单线程执行。第一个参数是队列的名称,在调试程序时会非常有用,所有尽量不要重名了。
- //(并行)
- 2. dispatch_queue_t queue = dispatch_queue_create("com.dispatch.concurrent", DISPATCH_QUEUE_CONCURRENT); //生成一个并发执行队列,block被分发到多个线程去执行
- //全局队列 (并行)
- 3. dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //获得程序进程缺省产生的并发队列,可设定优先级来选择高、中、低三个优先级队列。由于是系统默认生成的,所以无法调用dispatch_resume()和dispatch_suspend()来控制执行继续或中断。需要注意的是,三个队列不代表三个线程,可能会有更多的线程。并发队列可以根据实际情况来自动产生合理的线程数,也可理解为dispatch队列实现了一个线程池的管理,对于程序逻辑是透明的。
-
说明:全局并发队列的优先级
#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_BACKGROUND。Xcode调试时可以观察到正在使用的各个dispatch队列。
- 4. dispatch_queue_t queue = dispatch_get_main_queue(); //获得主线程的dispatch队列,实际是一个串行队列。同样无法控制主线程dispatch队列的执行继续或中断。
5.各种队列的执行效果
// dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// dispatch_queue_t queue=dispatch_queue_create("serial", DISPATCH_QUEUE_SERIAL);
//手动创建并发队列
dispatch_queue_t queue=dispatch_queue_create("com.dispatch.concurrent", DISPATCH_QUEUE_CONCURRENT);
//默认线程1
//sync同步不创建新线程 线程1
dispatch_sync(queue, ^{
NSLog(@"group1 @%@",[NSThread currentThread]);
});
//async异步创建线程2
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:5];
NSLog(@"group1 @%@",[NSThread currentThread]);
});
//创建线程3
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:5];
NSLog(@"group2@%@",[NSThread currentThread]);
});
//创建线程4
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:10];
NSLog(@"group@%@",[NSThread currentThread]);
});
NSLog(@"group3");//线程1
NSLog(@"15 group4");//线程1
[NSThread sleepForTimeInterval:7];//线程1
dispatch_suspend(queue);//线程管理 线程暂停
NSLog(@"group5");//线程1
dispatch_resume(queue);//线程管理 线程重新开始
解析结果 每一个线程单独运行 线程1
dispatch_sync(queue, ^{
NSLog(@"group1 @%@",[NSThread currentThread]);
});
线程2 3 4代码NSLog(@"group3");
NSLog(@"15 group4");//线程1
[NSThread sleepForTimeInterval:7];//线程1
dispatch_suspend(queue);//线程管理 线程暂停
NSLog(@"group5");//线程1
dispatch_resume(queue);//线程管理 线程重新开始
线程2
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:5]; 沉睡5秒
NSLog(@"group1 @%@",[NSThread currentThread]);
});
线程3
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:5];沉睡5秒
NSLog(@"group2@%@",[NSThread currentThread]);
});
线程4
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:10];沉睡10秒
NSLog(@"group@%@",[NSThread currentThread]);
});
运行开始 线程1同步输出结果group1 (线程2异步运行沉睡5秒 线程3沉睡5秒 线程4沉睡10秒继续运行下边代码 异步不阻塞主线程 线程1继续运行) 线程1输出group3 过group4 主线程沉睡7秒 (在7秒内 线程2和3 沉睡时间到 线程4时间未到) 输出 group1 group2 (7秒后主线程继续 线程停止dispatch_suspend所以线程3停止) 输出group5 (dispatch_resume线程恢复 线程4继续运行)输出线程group