iOS开发多线程网络———多线程概念及GCD
一.多线程的概念
1.什么是进程?
a.正在进行中的程序被称为进程,负责程序运行的内存分配
b.每一个进程都有自己独立的虚拟内存空间
2.什么是线程?
a.线程是进程中一个独立的执行路径(控制单元)
b.一个进程中至少包含一条线程,即主线程
(在iOS中主线程在栈区中区区只占1M,而子线程只有512k)
c. 线程可以将耗时的执行路径(如:网络请求)放在其他线程中执行被称为子线程
(注意:子线程运行完毕被主线程回收了,是杀不掉的,但是可以暂停或休眠)
d.创建线程的目的就是为了开启一条新的执行路径,运行指定的代码,与主线程中的代码实现同时运行
就是为了在一个CPU上实现快速切换!
3.多任务系统调度
当运行多个程序时,每个应用程序都是由操作系统分配短暂的时间片(Timeslice)轮流使用CPU,由于 CPU对每个
时间片的处理速度非常快(以微秒来计算的),因此用户看起来好像这些任务在同时执行的,但是在任意一个时刻点上,
CPU只会处理一个任务
4.使用多线程的利弊
当了解了多线程的概念之后,我们来看看有多线程都有哪些优势和弊端
A.优势
a.充分发挥多核处理优势,将不同线程任务分配给不同的处理器,真正进入"并行运算"状态
b.将耗时的任务分配到其他线程执行,由主线程负责统一更新界面回使应用程序更加流畅,用户体验更好
c.当硬件处理器的数量增加,程序会运行更快,而程序无需做任何调整
B.弊端
新建线程会消耗内存空间和CPU时间,线程太多会降低系统的运行性能
C.误区
多线程技术是为了并发执行多项任务,不会提高单个算法本身的执行效率 (并发:指两个或多个任务在同一时间间隔内发生)
iOS多线程技术有三种,分别是: GCD 、NSThread 、NSOperation/NSOperationQueue
二.GCD
1.什么是GCD
GCD为Grand Central Dispatch的缩写,简单的说就是是Apple在iOS4.0开发的一个多核编程较新的解决方法,用来优化应
用程序以支持多核处理器。它是基于C语言的底层API,用Block定义任务,使用起来非常灵活便捷,提供了更多的控制能力以及操作
队列中所不能使用的底层函数
2.GCD的核心思想
(1) GCD 的核心思想就是将操作放到队列中去执行
a.操作使用Blocks定义
b.队列负责调度热舞执行所在的线程以及具体的执行时间
c.队列的特点是先进先出(FIFO)的,新添加队列的操作都会排在队尾
(2)提示:GCD的函数都是以dispatch(分派、调度)开头的
(3)队列 (dispatch_queue_t)
a. 串行队列:队列中的任务只会顺序执行
b. 并行队列:队列中的任务通常会并发执行
(注意:队列不是线程,也不表示对应的CPU 队列就是负责调度!谁空闲,就把任务给谁!)
(4)操作
a.dispatch_async 异步操作,会并发执行,无法确定任务的执行顺序
b.dispatch_sync 同步操作,会依次顺序执行,能够决定任务的执行顺序
2.1 串行队列:队列中的任务只会顺序执行
串行队列的同步和异步任务代码演示:
1 #import "LDViewController.h"
3 @interface LDViewController ()
4
5 @end
6
7 @implementation LDViewController
8
9 - (void)viewDidLoad
10 {
11 [super viewDidLoad];
12
13 NSLog(@"%@",[NSThread currentThread]);
14
15 [self gcdDemo1];
16 }
17
18 #pragma mark - GCD方法
19 #pragma mark - 串行(一个接一个,排队跑步,保持队形)队列
20 - (void)gcdDemo1
21 {
22 //将操作放在队列中
23 //在C语言函数中,定义类型,绝大多数的结尾是_t 或者ref
24 //使用串行队列的异步任务非常有用!新建子线程是有开销的,不能无休止新建线程
25 //即可以保证效率 (新建一个子线程) , 又能够实现并发
26
27 //应用案例
28
29 //1>从网络上下载图片
30 //2>滤镜(高光,红眼……)
31
32 dispatch_queue_t LD = dispatch_queue_create("liudeng", DISPATCH_QUEUE_SERIAL);
33
34
35 //串行队列的同步任务,同样会在主线程上运行
36
37 for (int i = 0 ; i < 6; ++i) {
38 //同步任务:顺序执行
39 dispatch_sync(LD, ^{
40 NSLog(@"%@ %d", [NSThread currentThread],i);
41 });
42 }
43
44 for (int i = 0; i < 7; ++i) {
45 //异步任务 :并发执行,但是如果在串行队列中,仍然会依次顺序执行
46 dispatch_async(LD, ^{
47 //[NSThread currentThread] 可以在开发中,跟踪当前线程
48 //num = 1, 表示主线程
49 //num = 2, 表示第2个子线程……
50 NSLog(@"%@ %d",[NSThread currentThread], i);
51 });
52 }
53
54 }
55
56
57 @end
运行结果及总结:
a.在串行队列中,分别运行同步任务和异步任务时,结果都为下面有序结果 (可以看出异步任务在串行队列中也是有顺序的)
2014-06-14 00:07:31.339 GCD演练[1346:1303] <NSThread: 0x1093045e0>{name = (null), num = 2} 0
2014-06-14 00:07:31.340 GCD演练[1346:1303] <NSThread: 0x1093045e0>{name = (null), num = 2} 1
2014-06-14 00:07:31.341 GCD演练[1346:1303] <NSThread: 0x1093045e0>{name = (null), num = 2} 2
2014-06-14 00:07:31.341 GCD演练[1346:1303] <NSThread: 0x1093045e0>{name = (null), num = 2} 3
2014-06-14 00:07:31.342 GCD演练[1346:1303] <NSThread: 0x1093045e0>{name = (null), num = 2} 4
2014-06-14 00:07:31.342 GCD演练[1346:1303] <NSThread: 0x1093045e0>{name = (null), num = 2} 5
b.在串行队列中,同步任务在上,异步任务在下
2 2014-06-14 00:25:38.242 GCD演练[1432:60b] <NSThread: 0x109506690>{name = (null), num = 1} 0
3 2014-06-14 00:25:38.242 GCD演练[1432:60b] <NSThread: 0x109506690>{name = (null), num = 1} 1
4 2014-06-14 00:25:38.243 GCD演练[1432:60b] <NSThread: 0x109506690>{name = (null), num = 1} 2
5 2014-06-14 00:25:38.243 GCD演练[1432:60b] <NSThread: 0x109506690>{name = (null), num = 1} 3
6 2014-06-14 00:25:38.244 GCD演练[1432:60b] <NSThread: 0x109506690>{name = (null), num = 1} 4
7 2014-06-14 00:25:38.244 GCD演练[1432:60b] <NSThread: 0x109506690>{name = (null), num = 1} 5
8 2014-06-14 00:25:38.245 GCD演练[1432:60b] <NSThread: 0x109506690>{name = (null), num = 1} 6
9 2014-06-14 00:25:38.245 GCD演练[1432:1303] <NSThread: 0x1092799e0>{name = (null), num = 2} 0
10 2014-06-14 00:25:38.246 GCD演练[1432:1303] <NSThread: 0x1092799e0>{name = (null), num = 2} 1
11 2014-06-14 00:25:38.246 GCD演练[1432:1303] <NSThread: 0x1092799e0>{name = (null), num = 2} 2
12 2014-06-14 00:25:38.247 GCD演练[1432:1303] <NSThread: 0x1092799e0>{name = (null), num = 2} 3
13 2014-06-14 00:25:38.248 GCD演练[1432:1303] <NSThread: 0x1092799e0>{name = (null), num = 2} 4
14 2014-06-14 00:25:38.258 GCD演练[1432:1303] <NSThread: 0x1092799e0>{name = (null), num = 2} 5
c.在串行队列中,异步任务在上,同步任务在下 (可以看出队列的特点是先进先出(FIFO)的,新添加队列的操作都会排在队尾)
2 2014-06-14 00:23:43.753 GCD演练[1414:1303] <NSThread: 0x1092694a0>{name = (null), num = 2} 0
3 2014-06-14 00:23:43.753 GCD演练[1414:1303] <NSThread: 0x1092694a0>{name = (null), num = 2} 1
4 2014-06-14 00:23:43.754 GCD演练[1414:1303] <NSThread: 0x1092694a0>{name = (null), num = 2} 2
5 2014-06-14 00:23:43.754 GCD演练[1414:1303] <NSThread: 0x1092694a0>{name = (null), num = 2} 3
6 2014-06-14 00:23:43.755 GCD演练[1414:1303] <NSThread: 0x1092694a0>{name = (null), num = 2} 4
7 2014-06-14 00:23:43.755 GCD演练[1414:1303] <NSThread: 0x1092694a0>{name = (null), num = 2} 5
8 2014-06-14 00:23:43.756 GCD演练[1414:1303] <NSThread: 0x1092694a0>{name = (null), num = 2} 6
9 2014-06-14 00:23:43.756 GCD演练[1414:60b] <NSThread: 0x10931c500>{name = (null), num = 1} 0
10 2014-06-14 00:23:43.757 GCD演练[1414:60b] <NSThread: 0x10931c500>{name = (null), num = 1} 1
11 2014-06-14 00:23:43.757 GCD演练[1414:60b] <NSThread: 0x10931c500>{name = (null), num = 1} 2
12 2014-06-14 00:23:43.758 GCD演练[1414:60b] <NSThread: 0x10931c500>{name = (null), num = 1} 3
13 2014-06-14 00:23:43.758 GCD演练[1414:60b] <NSThread: 0x10931c500>{name = (null), num = 1} 4
14 2014-06-14 00:23:43.760 GCD演练[1414:60b] <NSThread: 0x10931c500>{name = (null), num = 1} 5
2.2 并行队列:队列中的任务通常会并发执行
并行队列的同步和异步任务代码演示:
2
3 @interface LDViewController ()
4
5 @end
6
7 @implementation LDViewController
8
9 - (void)viewDidLoad
10 {
11 [super viewDidLoad];
12
13 NSLog(@"%@",[NSThread currentThread]);
14
15 [self gcdDemo2];
16 }
17
18 #pragma mark - GCD方法
19
20 #pragma mark - 并行 (并排跑,类似于赛跑)
21 - (void)gcdDemo2
22 {
23 //特点:没有队形,执行顺序程序员不能控制
24 //应用场景:并发执行任务,没有先后顺序
25 //并行队列容易出错!并行队列不能控制新建线程的数量!
26 dispatch_queue_t LD = dispatch_queue_create("liudeng", DISPATCH_QUEUE_CONCURRENT);
27
28 for (int i = 0 ; i < 7; ++i) {
29 //同步任务:顺序执行
30 dispatch_sync(LD, ^{
31 NSLog(@"%@ %d", [NSThread currentThread],i);
32 });
33 }
34
35 for (int i = 0; i < 6; ++i) {
36 //异步任务
37 dispatch_async(LD, ^{
38 //[NSThread currentThread] 可以在开发中,跟踪当前线程
39 //num = 1, 表示主线程
40 //num = 2, 表示第2个子线程……
41 NSLog(@"%@ %d",[NSThread currentThread], i);
42 });
43 }
44 }
运行结果及总结:
a.在并行队列中,单独运行同步任务结果 (可以看出同步任务在并行队列中是有顺序的)
2 2014-06-14 00:42:54.174 GCD演练[1503:60b] <NSThread: 0x10921c630>{name = (null), num = 1} 0
3 2014-06-14 00:42:54.175 GCD演练[1503:60b] <NSThread: 0x10921c630>{name = (null), num = 1} 1
4 2014-06-14 00:42:54.175 GCD演练[1503:60b] <NSThread: 0x10921c630>{name = (null), num = 1} 2
5 2014-06-14 00:42:54.176 GCD演练[1503:60b] <NSThread: 0x10921c630>{name = (null), num = 1} 3
6 2014-06-14 00:42:54.176 GCD演练[1503:60b] <NSThread: 0x10921c630>{name = (null), num = 1} 4
7 2014-06-14 00:42:54.177 GCD演练[1503:60b] <NSThread: 0x10921c630>{name = (null), num = 1} 5
b.在并行队列中,单独运行异步任务结果 (可以看出异步任务在并行队列中是没有顺序的)
2 2014-06-14 00:45:51.927 GCD演练[1522:3007] <NSThread: 0x109229b90>{name = (null), num = 5} 1
3 2014-06-14 00:45:51.927 GCD演练[1522:3503] <NSThread: 0x1092081c0>{name = (null), num = 3} 2
4 2014-06-14 00:45:51.927 GCD演练[1522:3603] <NSThread: 0x109420830>{name = (null), num = 4} 3
5 2014-06-14 00:45:51.927 GCD演练[1522:1303] <NSThread: 0x10921c760>{name = (null), num = 2} 0
6 2014-06-14 00:45:51.928 GCD演练[1522:3007] <NSThread: 0x109229b90>{name = (null), num = 5} 4
7 2014-06-14 00:45:51.930 GCD演练[1522:3603] <NSThread: 0x109420830>{name = (null), num = 4} 6
c.在并行队列中,同步任务在上,异步任务在下结果 (同步任务是有序的,而且还是在主线程上执行,只有同步任务执行完毕之后,异步任务才开始工作)
2 2014-06-14 00:48:50.232 GCD演练[1541:60b] <NSThread: 0x10931c500>{name = (null), num = 1} 0
3 2014-06-14 00:48:50.233 GCD演练[1541:60b] <NSThread: 0x10931c500>{name = (null), num = 1} 1
4 2014-06-14 00:48:50.233 GCD演练[1541:60b] <NSThread: 0x10931c500>{name = (null), num = 1} 2
5 2014-06-14 00:48:50.234 GCD演练[1541:60b] <NSThread: 0x10931c500>{name = (null), num = 1} 3
6 2014-06-14 00:48:50.234 GCD演练[1541:60b] <NSThread: 0x10931c500>{name = (null), num = 1} 4
7 2014-06-14 00:48:50.235 GCD演练[1541:60b] <NSThread: 0x10931c500>{name = (null), num = 1} 5
8 2014-06-14 00:48:50.235 GCD演练[1541:60b] <NSThread: 0x10931c500>{name = (null), num = 1} 6
9 2014-06-14 00:48:50.236 GCD演练[1541:1303] <NSThread: 0x1092205c0>{name = (null), num = 2} 0
10 2014-06-14 00:48:50.236 GCD演练[1541:3603] <NSThread: 0x109220730>{name = (null), num = 3} 3
11 2014-06-14 00:48:50.236 GCD演练[1541:3403] <NSThread: 0x10934e550>{name = (null), num = 5} 1
12 2014-06-14 00:48:50.236 GCD演练[1541:3503] <NSThread: 0x10934cc40>{name = (null), num = 4} 2
13 2014-06-14 00:48:50.237 GCD演练[1541:1303] <NSThread: 0x1092205c0>{name = (null), num = 2} 4
14 2014-06-14 00:48:50.237 GCD演练[1541:3403] <NSThread: 0x10934e550>{name = (null), num = 5} 6
d.在并行队列中,异步任务在上,同步任务在下结果 (没有队行,执行顺序程序员不能控制)
2 2014-06-14 00:54:38.680 GCD演练[1559:60b] <NSThread: 0x10960f2c0>{name = (null), num = 1} 0
3 2014-06-14 00:54:38.681 GCD演练[1559:1303] <NSThread: 0x10937c290>{name = (null), num = 2} 0
4 2014-06-14 00:54:38.681 GCD演练[1559:3503] <NSThread: 0x109623b30>{name = (null), num = 4} 2
5 2014-06-14 00:54:38.681 GCD演练[1559:3403] <NSThread: 0x10cf04e00>{name = (null), num = 3} 1
6 2014-06-14 00:54:38.681 GCD演练[1559:3603] <NSThread: 0x10cf07580>{name = (null), num = 5} 3
7 2014-06-14 00:54:38.681 GCD演练[1559:60b] <NSThread: 0x10960f2c0>{name = (null), num = 1} 1
8 2014-06-14 00:54:38.684 GCD演练[1559:60b] <NSThread: 0x10960f2c0>{name = (null), num = 1} 2
9 2014-06-14 00:54:38.684 GCD演练[1559:3403] <NSThread: 0x10cf04e00>{name = (null), num = 3} 6
10 2014-06-14 00:54:38.681 GCD演练[1559:3503] <NSThread: 0x109623b30>{name = (null), num = 4} 5
11 2014-06-14 00:54:38.685 GCD演练[1559:60b] <NSThread: 0x10960f2c0>{name = (null), num = 1} 3
12 2014-06-14 00:54:38.681 GCD演练[1559:1303] <NSThread: 0x10937c290>{name = (null), num = 2} 4
13 2014-06-14 00:54:38.685 GCD演练[1559:60b] <NSThread: 0x10960f2c0>{name = (null), num = 1} 4
14 2014-06-14 00:54:38.685 GCD演练[1559:60b] <NSThread: 0x10960f2c0>{name = (null), num = 1} 5
2.3 全局队列:全局队列是系统的,直接通过(get)拿过来用就可以了
2
3 #pragma mark - 全局队列 (苹果为了方便多线程的设计,提供一个全局队列,供所有的APP共同使用)
4 - (void)gcdDemo3
5 {
6 dispatch_queue_t LD = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
7 for (int i = 0 ; i < 7; ++i) {
8 //同步任务:顺序执行
9 dispatch_sync(LD, ^{
10 NSLog(@"%@ %d", [NSThread currentThread],i);
11 });
12 }
13
14 for (int i = 0; i < 7; ++i) {
15 //异步任务 :并发执行,但是如果在串行队列中,仍然会依次顺序执行
16 dispatch_async(LD, ^{
17 //[NSThread currentThread] 可以在开发中,跟踪当前线程
18 //num = 1, 表示主线程
19 //num = 2, 表示第2个子线程……
20 NSLog(@"%@ %d",[NSThread currentThread], i);
21 });
22 }
全局队列和并行队列很类似,比较如下:
a.全局队列不需要创建,直接get就能用
b.两个队列的执行效果相同
c.全局队列没有名称,调试时,无法确认准确队列
2.4 主(线程)队列:
2 - (void)gcdDemo4
3 {
4 //每一个应用程序都只有一个主线程
5 //为什么需要在主线程上工作?
6 //在IOS开发中,所有UI的更新工作,都必须在主线程上执行!
7 dispatch_queue_t LD = dispatch_get_main_queue();
8 //主线程是一直工作的,除非将程序杀掉,否则主线程的工作永远不会结束
9 //同步任务,主线程会阻塞
10 // dispatch_sync(LD, ^{
11 // NSLog(@"你好");
12 // });
13
14 for (int i = 0; i < 6; ++i) {
15 //异步任务,在主线程上运行,同时是保持队形的
16 dispatch_async(LD, ^{
17 NSLog(@"%@ %d", [NSThread currentThread], i);
18 });
19 }
3.GCD小结:
串行队列,同步任务,不需要新建线程
串行队列,异步任务,需要一个子线程,线程的创建和回收不需要程序员参与! “是最安全的一种选择,串行队列是get不到的,只能创建”
并行队列,同步任务,不需要创建线程
并行队列,异步任务,有多少个任务,就开N个线程执行
通过GCD,开发者不用再直接跟线程打交道,只需要向队列中添加代码块即可
GCD在后端管理着一个线程池,GCD不仅决定着代码块将在哪个线程被执行,它还根据可用的系统资源对这些线程进行
管理,从而让开发者从线程管理的工作中解放出来,通过集中的管理线程,缓解大量线程被创建问题
使用GCD,开发者可以将工作考虑为一个队列,而不是一堆线程,这种并行的抽象模型更容易掌握和使用